diff --git a/map/src/infoblock/components/wpt/WptTagInfo.jsx b/map/src/infoblock/components/wpt/WptTagInfo.jsx index d4c8a6e63..5393f48df 100644 --- a/map/src/infoblock/components/wpt/WptTagInfo.jsx +++ b/map/src/infoblock/components/wpt/WptTagInfo.jsx @@ -29,6 +29,7 @@ export default function WptTagInfo({ tag = null, baseTag = null, copy = false, s } useEffect(() => { + setNewTag(null); if (tag?.collapsable) { const items = tag.value.split(SEPARATOR); if (items.length > 1) { diff --git a/map/src/infoblock/components/wpt/WptTagsProvider.js b/map/src/infoblock/components/wpt/WptTagsProvider.js index 6722f3600..d83a7e28c 100644 --- a/map/src/infoblock/components/wpt/WptTagsProvider.js +++ b/map/src/infoblock/components/wpt/WptTagsProvider.js @@ -17,7 +17,7 @@ import { ReactComponent as DisplayLanguageIcon } from '../../../assets/icons/ic_ import { changeIconColor } from '../../../map/markers/MarkerOptions'; import { createPoiCache, getIconNameForPoiType, updatePoiCache } from '../../../manager/PoiManager'; import React from 'react'; -import { apiGet } from '../../../util/HttpApi'; +import { apiGet, apiPost } from '../../../util/HttpApi'; import { parseTagWithLang } from '../../../manager/SearchManager'; import { localizeWeekTokens } from '../../../util/dateFmt'; import { @@ -52,7 +52,6 @@ const EMAIL = 'email'; const WEBSITE = 'website'; const CUISINE = 'cuisine'; export const CUISINE_PREFIX = 'cuisine_'; -const ROUTE = 'route'; export const IMAGE_OSM_TAG = 'image'; export const MAPILLARY_OSM_TAG = 'mapillary'; export const WIKIDATA = 'wikidata'; @@ -61,14 +60,14 @@ const INSTAGRAM = 'instagram'; export const OSM_PREFIX = 'osm_tag_'; const COLLAPSABLE_PREFIX = 'collapsable_'; export const COLOR_NAME_EXTENSION = 'color'; -export const ICON_NAME_EXTENSION = 'icon'; +const ICON_NAME_EXTENSION = 'icon'; export const BACKGROUND_TYPE_EXTENSION = 'background'; -export const PROFILE_TYPE_EXTENSION = 'profile'; -export const ADDRESS_EXTENSION = 'address'; -export const AMENITY_ORIGIN_EXTENSION = 'amenity_origin'; export const NAME = 'name'; export const EN_NAME = 'en_name'; export const ALT_NAME = 'osm_tag_alt_name'; +const ORIGINAL_ICON = 'originalIcon'; +const MARKER_ICON_SVG = 'svg'; +const MARKER_OBJ_ID = 'idObj'; // from Amenity object export const POI_NAME = WEB_POI_PREFIX + 'name'; @@ -103,20 +102,7 @@ export const PARAM_FIELDS = 'fields=id,geometry,compass_angle,captured_at,camera export const TITLE = 'title'; -const HIDDEN_EXTENSIONS = [ - COLOR_NAME_EXTENSION, - ICON_NAME_EXTENSION, - BACKGROUND_TYPE_EXTENSION, - PROFILE_TYPE_EXTENSION, - ADDRESS_EXTENSION, - AMENITY_ORIGIN_EXTENSION, - AMENITY_PREFIX + NAME, - AMENITY_PREFIX + TYPE, - AMENITY_PREFIX + SUBTYPE, -]; - -const HIDDEN_EXTENSIONS_POI = [ - ...HIDDEN_EXTENSIONS, +const WEB_TAGS_TO_SKIP = [ ICON_KEY_NAME, POI_ICON_NAME, TYPE_OSM_TAG, @@ -128,6 +114,7 @@ const HIDDEN_EXTENSIONS_POI = [ POI_NAME, POI_ID, POI_OSM_URL, + MARKER_OBJ_ID, ]; export const SEPARATOR = ';'; @@ -232,145 +219,186 @@ async function getWptTags(obj, type, ctx) { } } - tags = fixTagsKeys(tags); + const poiNameTags = {}; + const mainTags = {}; for (const [key, value] of Object.entries(tags)) { - if (!shouldSkipKey(key)) { - let tagObj = {}; - tagObj.key = key; - if (key.includes(WIKIPEDIA)) { - tagObj.value = getWikipediaURL(key, value); - } else { - tagObj.value = value; - } - tagObj.isUrl = isUrl(tagObj.value); - if (!tagObj.isUrl) { - tagObj.socialMediaUrl = getSocialMediaUrl(key, value); - if (tagObj.socialMediaUrl != null) { - tagObj.isUrl = true; - } + if (key.startsWith(POI_NAME) && value) { + poiNameTags[key] = value; + } else if (key.includes(WIKIDATA) || key.includes(WIKIPEDIA)) { + const tagKey = key.includes(WIKIDATA) ? WIKIDATA : WIKIPEDIA; + const tagObj = await buildTagObj({ key: tagKey, value: value, lang: null, ctx, subtypeTag }); + if (tagObj) { + res.push(tagObj); } + } else { + mainTags[key] = value; + } + } - switch (key) { - case WIKIPEDIA: - tagObj.icon = ; - break; - case CUISINE: - tagObj.icon = ; - break; - case SERVICE_TIMES: - case COLLECTION_TIMES: - tagObj.icon = ; - tagObj.needLinks = false; - tagObj.textPrefix = value; - break; - case OPENING_HOURS: - tagObj.icon = ; - break; - case PHONE: - tagObj.icon = ; - tagObj.isPhoneNumber = true; - break; - case MOBILE: - tagObj.icon = ; - tagObj.isPhoneNumber = true; - break; - case WEBSITE: - tagObj.icon = ; - tagObj.isUrl = true; - break; - case DESCRIPTION: - tagObj.icon = ; - tagObj.desc = true; - break; - case INSTAGRAM: - tagObj.icon = ; - break; - case EMAIL: - tagObj.isEmail = true; - tagObj.icon = ; - break; - default: - if (key === 'addr:housename' || key === 'whitewater:rapid_name') { - tagObj.icon = ; - } else if (key.startsWith('operator') || key.startsWith('brand')) { - tagObj.icon = ; - } else if (key === 'internet_access_fee_yes') { - tagObj.icon = ; - } else if (key.includes('internet_access')) { - const prepValue = value.replace(TYPE, '').replace('__', '_'); - const svgData = await getSvgIcon({ value: prepValue, ctx }); - tagObj.icon = getIcon(svgData, DEFAULT_TAG_ICON_SIZE, DEFAULT_TAG_ICON_COLOR); - } else if (parseTagWithLang(key).lang) { - tagObj.icon = ; - } else { - const svgData = await getSvgIcon({ key, value, ctx }); - tagObj.icon = getIcon(svgData, DEFAULT_TAG_ICON_SIZE, DEFAULT_TAG_ICON_COLOR); - } - } + const poiNameTagObj = await buildPoiNameTagObj(poiNameTags, ctx, subtypeTag); + if (poiNameTagObj) { + res.push(poiNameTagObj); + } - const formattedPrefixAndText = getFormattedPrefixAndText( - key, - tagObj.textPrefix, - value, - subtypeTag, - ctx - ); - tagObj.textPrefix = formattedPrefixAndText[0]; - tagObj.value = formattedPrefixAndText[1]; - - if (key.startsWith(COLLAPSABLE_PREFIX)) { - tagObj.collapsable = true; - tagObj.textPrefix = key.replace(COLLAPSABLE_PREFIX, ''); - if (tagObj.textPrefix === CUISINE) { - tagObj.icon = ; - hasCuisine = true; - } - } + tags = filterWebKeys(mainTags); + const tagList = await fetchVisibleTags(tags); - if (tagObj.key === OPENING_HOURS) { - tagObj.value = localizeWeekTokens(tagObj.value); - } + for (const entry of tagList) { + let tagObj = await buildTagObj({ key: entry.key, value: entry.value, lang: entry.lang, ctx, subtypeTag }); - if (tagObj.key.startsWith(POI_NAME)) { - tagObj.key = tagObj.key.replace(POI_NAME, 'shared_string_name'); - tagObj.textPrefix = tagObj.key; - } + if (entry.otherLangs?.length) { + tagObj.otherLangs = await buildOtherLangTags(entry.otherLangs, ctx, subtypeTag); + } - if (key.includes(WIKIDATA)) { - tagObj = addWikidataTags(key, value, tagObj); - } - res.push(tagObj); + if (tagObj.collapsable && tagObj.textPrefix === CUISINE) { + hasCuisine = true; } + res.push(tagObj); } if (hasCuisine) { res = res.filter((t) => t.key !== CUISINE); } } - res = res.filter((t) => !t.key.startsWith(WEB_PREFIX)); - res = mergeTagsWithLang(res); return { res, id, type: typeTag, subtype: subtypeTag }; } -function mergeTagsWithLang(tags) { - tags.forEach((tag) => { - if (tag.key.includes(':')) { - const arr = tag.key.split(':'); - tag.key = arr[0]; - tag.lang = arr[1]; +async function buildTagObj({ key, value, lang, ctx, subtypeTag }) { + let tagObj = { key }; + tagObj.value = key.includes(WIKIPEDIA) ? getWikipediaURL(key, value) : value; + tagObj.isUrl = isUrl(tagObj.value); + if (!tagObj.isUrl) { + tagObj.socialMediaUrl = getSocialMediaUrl(key, value); + if (tagObj.socialMediaUrl != null) { + tagObj.isUrl = true; } - }); - let tagsWithLang = tags.filter((tag) => tag.lang); - tagsWithLang.forEach((tag) => { - if (tags.includes(tag)) { - const sameTags = tags.filter((t) => t.key === tag.key && t !== tag); - if (sameTags?.length > 0) { - tag.otherLangs = sameTags; - tags = tags.filter((t) => !sameTags.includes(t)); - } + } + + Object.assign(tagObj, await getTagIconProps({ key, value, lang, ctx })); + + const [formattedPrefix, formattedValue] = getFormattedPrefixAndText(key, tagObj.textPrefix, value, subtypeTag, ctx); + tagObj.textPrefix = formattedPrefix; + tagObj.value = formattedValue; + + applyCollapsablePrefix(tagObj, key); + applySharedNameTag(tagObj); + + if (tagObj.key === OPENING_HOURS) { + tagObj.value = localizeWeekTokens(tagObj.value); + } + + if (key.includes(WIKIDATA)) { + tagObj = addWikidataTags(key, value, tagObj); + } + + if (lang) { + tagObj.lang = lang; + tagObj.textPrefix = `${tagObj.textPrefix}:${lang}`; + } + + return tagObj; +} + +async function getTagIconProps({ key, value, lang, ctx }) { + switch (key) { + case WIKIPEDIA: + return { icon: }; + case CUISINE: + return { icon: }; + case SERVICE_TIMES: + case COLLECTION_TIMES: + return { icon: , needLinks: false, textPrefix: value }; + case OPENING_HOURS: + return { icon: }; + case PHONE: + return { icon: , isPhoneNumber: true }; + case MOBILE: + return { icon: , isPhoneNumber: true }; + case WEBSITE: + return { icon: , isUrl: true }; + case DESCRIPTION: + return { icon: , desc: true }; + case INSTAGRAM: + return { icon: }; + case EMAIL: + return { icon: , isEmail: true }; + case 'addr:housename': + case 'whitewater:rapid_name': + return { icon: }; + case 'internet_access_fee_yes': + return { icon: }; + default: + return await getOtherTagIconProps({ key, value, lang, ctx }); + } +} + +async function getOtherTagIconProps({ key, value, lang, ctx }) { + if (key.startsWith('operator') || key.startsWith('brand')) { + return { icon: }; + } + if (key.includes('internet_access')) { + const prepValue = value.replace(TYPE, '').replace('__', '_'); + const svgData = await getSvgIcon({ value: prepValue, ctx }); + return { icon: getIcon(svgData, DEFAULT_TAG_ICON_SIZE, DEFAULT_TAG_ICON_COLOR) }; + } + if (lang || parseTagWithLang(key).lang) { + return { icon: }; + } + const svgData = await getSvgIcon({ key, value, ctx }); + + return { icon: getIcon(svgData, DEFAULT_TAG_ICON_SIZE, DEFAULT_TAG_ICON_COLOR) }; +} + +function applyCollapsablePrefix(tagObj, key) { + if (key.startsWith(COLLAPSABLE_PREFIX)) { + tagObj.collapsable = true; + tagObj.textPrefix = key.replace(COLLAPSABLE_PREFIX, ''); + if (tagObj.textPrefix === CUISINE) { + tagObj.icon = ; } + } +} + +function applySharedNameTag(tagObj) { + if (tagObj.key.startsWith(POI_NAME)) { + tagObj.key = tagObj.key.replace(POI_NAME, 'shared_string_name'); + tagObj.textPrefix = tagObj.key; + } +} + +async function buildPoiNameTagObj(poiNameTags, ctx, subtypeTag) { + const entries = Object.entries(poiNameTags).map(([key, value]) => { + const [base, lang] = key.split(':'); + return lang ? { key: base, value, lang } : { key: base, value }; + }); + + const mainEntry = entries.find((entry) => entry.lang) ?? entries[0]; + if (!mainEntry) { + return null; + } + + const tagObj = await buildTagObj({ + key: mainEntry.key, + value: mainEntry.value, + lang: mainEntry.lang, + ctx, + subtypeTag, }); - return tags; + const otherEntries = entries.filter((entry) => entry !== mainEntry); + if (otherEntries.length > 0) { + tagObj.otherLangs = await buildOtherLangTags(otherEntries, ctx, subtypeTag); + } + + return tagObj; +} + +async function buildOtherLangTags(entries, ctx, subtypeTag) { + const otherLangs = []; + for (const entry of entries) { + otherLangs.push(await buildTagObj({ key: entry.key, value: entry.value, lang: entry.lang, ctx, subtypeTag })); + } + + return otherLangs; } export async function addPoiTypeTag({ @@ -397,24 +425,37 @@ export async function addPoiTypeTag({ return tagObj; } -function fixTagsKeys(tags) { +async function fetchVisibleTags(tags) { + if (Object.keys(tags).length === 0) return []; + tags = Object.fromEntries( + Object.entries(tags).map(([key, value]) => [ + key, + typeof value === 'number' || typeof value === 'boolean' ? String(value) : value, + ]) + ); + let response = await apiPost(`${process.env.REACT_APP_USER_API_SITE}/search/get-visible-tags`, tags, { + apiCache: true, + }); + + return Array.isArray(response?.data) ? response.data : []; +} + +function filterWebKeys(tags) { let res = {}; for (const [key, value] of Object.entries(tags)) { - let newKey = key; - if (key === AMENITY_PREFIX + OPENING_HOURS) { - newKey = key.replace(AMENITY_PREFIX, ''); - } else if ( - key.startsWith(AMENITY_PREFIX) || + if ( + key.startsWith(WEB_PREFIX) || key.startsWith(ALT_NAME) || - HIDDEN_EXTENSIONS.includes(key) || - HIDDEN_EXTENSIONS_POI.includes(key) + WEB_TAGS_TO_SKIP.includes(key) || + key.startsWith(ORIGINAL_ICON) || + key === MARKER_ICON_SVG || + key === ICON_NAME_EXTENSION ) { continue; - } else { - newKey = key.replace(OSM_PREFIX, ''); } - res[newKey] = value; + res[key] = value; } + return res; } @@ -613,17 +654,6 @@ function getWikipediaURL(key, value) { return value; } -function shouldSkipKey(key) { - return ( - key === 'idObj' || - key === 'name' || - key === 'subway_region' || - key === 'note' || - key === 'lang_yes' || - key.includes(ROUTE) - ); -} - export function openWikipediaContent(tag, setDevWikiContent) { if (tag.key === WIKIPEDIA) { getWikipediaContent(tag).then((data) => { @@ -711,7 +741,7 @@ function parseUrl(url, site) { } export function filterTag(tag) { - return tag.key !== WIKIMEDIA_COMMONS && !otherImgTags(tag.key) && tag.key !== 'svg' && tag.key !== 'type'; + return tag.key !== WIKIMEDIA_COMMONS && !otherImgTags(tag.key) && tag.key !== MARKER_ICON_SVG && tag.key !== 'type'; } export const otherImgTags = (tag) => {