import { Store, UIEventSource } from "../../Logic/UIEventSource" import EditableTagRendering from "./EditableTagRendering" import QuestionBox from "./QuestionBox" import Combine from "../Base/Combine" import TagRenderingAnswer from "./TagRenderingAnswer" import ScrollableFullScreen from "../Base/ScrollableFullScreen" import Constants from "../../Models/Constants" import SharedTagRenderings from "../../Customizations/SharedTagRenderings" import BaseUIElement from "../BaseUIElement" import { VariableUiElement } from "../Base/VariableUIElement" import DeleteWizard from "./DeleteWizard" import SplitRoadWizard from "./SplitRoadWizard" import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import { Utils } from "../../Utils" import MoveWizard from "./MoveWizard" import Toggle from "../Input/Toggle" import Lazy from "../Base/Lazy" import FeaturePipelineState from "../../Logic/State/FeaturePipelineState" import Svg from "../../Svg" import Translations from "../i18n/Translations" export default class FeatureInfoBox extends ScrollableFullScreen { public constructor( tags: UIEventSource, layerConfig: LayerConfig, state: FeaturePipelineState, options?: { hashToShow?: string isShown?: UIEventSource setHash?: true | boolean } ) { const showAllQuestions = state.featureSwitchShowAllQuestions.map( (fsShow) => fsShow || state.showAllQuestionsAtOnce.data, [state.showAllQuestionsAtOnce] ) super( () => FeatureInfoBox.GenerateTitleBar(tags, layerConfig, state), () => FeatureInfoBox.GenerateContent(tags, layerConfig, state, showAllQuestions), options?.hashToShow ?? tags.data.id ?? "item", options?.isShown, options ) if (layerConfig === undefined) { throw "Undefined layerconfig" } } public static GenerateTitleBar( tags: UIEventSource, layerConfig: LayerConfig, state: {} ): BaseUIElement { const title = new TagRenderingAnswer( tags, layerConfig.title ?? new TagRenderingConfig("POI"), state ).SetClass("break-words font-bold sm:p-0.5 md:p-1 sm:p-1.5 md:p-2 text-2xl") const titleIcons = new Combine( layerConfig.titleIcons.map((icon) => { return new TagRenderingAnswer( tags, icon, state, "block h-8 max-h-8 align-baseline box-content sm:p-0.5 titleicon" ) }) ).SetClass("flex flex-row flex-wrap pt-0.5 sm:pt-1 items-center mr-2") return new Combine([ new Combine([title, titleIcons]).SetClass( "flex flex-col sm:flex-row flex-grow justify-between" ), ]) } public static GenerateContent( tags: UIEventSource, layerConfig: LayerConfig, state: FeaturePipelineState, showAllQuestions?: Store ): BaseUIElement { return new Toggle( new Combine([ Svg.delete_icon_svg().SetClass("w-8 h-8"), Translations.t.delete.isDeleted, ]).SetClass("flex justify-center font-bold items-center"), FeatureInfoBox.GenerateMainContent(tags, layerConfig, state, showAllQuestions), tags.map((t) => t["_deleted"] == "yes") ) } private static GenerateMainContent( tags: UIEventSource, layerConfig: LayerConfig, state: FeaturePipelineState ): BaseUIElement { let questionBoxes: Map = new Map() const t = Translations.t.general const allGroupNames = Utils.Dedup(layerConfig.tagRenderings.map((tr) => tr.group)) const withQuestion = layerConfig.tagRenderings.filter( (tr) => tr.question !== undefined ).length const allRenderings: BaseUIElement[] = [ new VariableUiElement( tags .map((data) => data["_newly_created"]) .map((isCreated) => { if (isCreated === undefined) { return undefined } const createdDate = new Date(isCreated) const secondsSinceCreation = (Date.now() - createdDate.getTime()) / 1000 if (secondsSinceCreation >= 60 * 5) { return undefined } const els = [] const thanks = new Combine([ Svg.party_svg().SetClass( "w-12 h-12 shrink-0 p-1 m-1 bg-white rounded-full block" ), t.newlyCreated, ]).SetClass("flex w-full thanks content-center") els.push(thanks) if (withQuestion > 0) { els.push(t.feelFreeToSkip) } return new Combine(els).SetClass("pb-4 mb-4 border-b block border-black") }) ), ] for (let i = 0; i < allGroupNames.length; i++) { const groupName = allGroupNames[i] const trs = layerConfig.tagRenderings.filter((tr) => tr.group === groupName) const renderingsForGroup: (EditableTagRendering | BaseUIElement)[] = [] const innerClasses = "block w-full break-word text-default m-1 p-1 border-b border-gray-200 mb-2 pb-2" for (const tr of trs) { if (tr.question === null || tr.id === "questions") { // This is a question box! const questionBox = questionBoxes.get(tr.group) questionBoxes.delete(tr.group) if (tr.render !== undefined) { questionBox.SetClass("text-sm") const renderedQuestion = new TagRenderingAnswer( tags, tr, state, tr.group + " questions", "", { specialViz: new Map([ ["questions", questionBox], ]), } ) const possiblyHidden = new Toggle( renderedQuestion, undefined, questionBox.restingQuestions.map((ls) => ls?.length > 0) ) renderingsForGroup.push(possiblyHidden) } else { renderingsForGroup.push(questionBox) } } else { let classes = innerClasses let isHeader = renderingsForGroup.length === 0 && i > 0 if (isHeader) { // This is the first element of a group! // It should act as header and be sticky classes = "" } const etr = new EditableTagRendering(tags, tr, layerConfig.units, state, { innerElementClasses: innerClasses, }) if (isHeader) { etr.SetClass("sticky top-0") } renderingsForGroup.push(etr) } } allRenderings.push(...renderingsForGroup) } allRenderings.push( new Toggle( new Lazy(() => FeatureInfoBox.createEditElements(questionBoxes, layerConfig, tags, state) ), undefined, state.featureSwitchUserbadge ) ) return new Combine(allRenderings).SetClass("block") } /** * All the edit elements, together (note that the question boxes are passed though) * @param questionBoxes * @param layerConfig * @param tags * @param state * @private */ private static createEditElements( questionBoxes: Map, layerConfig: LayerConfig, tags: UIEventSource, state: FeaturePipelineState ): BaseUIElement { let editElements: BaseUIElement[] = [] questionBoxes.forEach((questionBox) => { editElements.push(questionBox) }) editElements.push( new VariableUiElement( state.osmConnection.userDetails .map((ud) => ud.csCount) .map( (csCount) => { if ( csCount <= Constants.userJourney.historyLinkVisible && state.featureSwitchIsDebugging.data == false && state.featureSwitchIsTesting.data === false ) { return undefined } return new TagRenderingAnswer( tags, SharedTagRenderings.SharedTagRendering.get("last_edit"), state ) }, [state.featureSwitchIsDebugging, state.featureSwitchIsTesting] ) ) ) return new Combine(editElements).SetClass("flex flex-col") } }