/* * Copyright (C) 2025 TomTom Navigation B.V. * Licensed under the Apache License, Version 2.0 */ import type { DelayMagnitude } from "@tomtom-org/maps-sdk/core"; import type { TrafficIncidentsModuleFeature } from "@tomtom-org/maps-sdk/map"; import { escapeHtml } from "./poi-popup"; /** The incident properties TrafficIncidentsModule gives its events and getRenderedFeatures(). */ export type IncidentProperties = TrafficIncidentsModuleFeature["properties"]; const ICON_WARNING = ``; const ICON_LOCATION = ``; const ICON_CLOCK = ``; const MAGNITUDE_STYLES: Record = { unknown: { label: "Unknown", color: "#6b7280" }, minor: { label: "Minor", color: "#ca8a04" }, moderate: { label: "Moderate", color: "#ea580c" }, major: { label: "Major", color: "#dc2626" }, indefinite: { label: "Indefinite", color: "#991b1b" }, }; function row(icon: string, content: string, color?: string): string { const style = color ? ` style="color:${color}"` : ""; return `
${icon}${content}
`; } /** "road-closed" → "Road closed" */ function categoryLabel(category: string): string { const words = category.replace(/-/g, " "); return words.charAt(0).toUpperCase() + words.slice(1); } function formatDate(date: Date): string { return date.toLocaleDateString(undefined, { month: "short", day: "numeric", year: "numeric" }); } export function buildIncidentPopupHtml(props: IncidentProperties): string { const category = props.category ? categoryLabel(props.category) : ""; const magnitude = MAGNITUDE_STYLES[props.magnitudeOfDelay]; const title = props.description || category || (magnitude ? `${magnitude.label} congestion` : "Traffic"); let html = `
${escapeHtml(title)}
`; if (props.description && category) { html += row(ICON_WARNING, `${escapeHtml(category)}`); } if (magnitude) { html += row( ICON_WARNING, `${magnitude.label}`, magnitude.color ); } const road = [props.roadCategory, props.roadSubcategory].filter(Boolean).join(" · "); if (road) html += row(ICON_LOCATION, `${escapeHtml(road)}`); if (props.startTime) { const end = props.endTime ? ` → ${formatDate(props.endTime)}` : ""; html += row(ICON_CLOCK, `${escapeHtml(formatDate(props.startTime) + end)}`); } const delay = props.delayInSeconds ?? 0; if (delay > 0) { const minutes = Math.round(delay / 60); html += row( ICON_CLOCK, `${minutes > 0 ? `${minutes} min delay` : `${delay}s delay`}` ); } const reports = props.numberOfReports ?? 0; if (reports > 0) { html += row(ICON_LOCATION, `${reports} report${reports > 1 ? "s" : ""}`); } return `${html}
`; }