diff --git a/src/Components/Map/Layer.tsx b/src/Components/Map/Layer.tsx index d3434e05..95682484 100644 --- a/src/Components/Map/Layer.tsx +++ b/src/Components/Map/Layer.tsx @@ -1,35 +1,38 @@ import * as React from 'react' import { Marker, Tooltip, useMap, useMapEvents } from 'react-leaflet' -import { Item, LayerProps } from '../../types' +import { Item, LayerProps, Tag } from '../../types' import MarkerIconFactory from '../../Utils/MarkerIconFactory' import { ItemViewPopup } from './Subcomponents/ItemViewPopup' import { useItems, useSetItemsApi, useSetItemsData } from './hooks/useItems' -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { ItemFormPopup } from './Subcomponents/ItemFormPopup' import { useFilterTags, useIsLayerVisible } from './hooks/useFilter' -import { useGetItemTags } from './hooks/useTags' +import { useAddTag, useAllTagsLoaded, useGetItemTags, useTags } from './hooks/useTags' import { useAddMarker, useAddPopup, useLeafletRefs } from './hooks/useLeafletRefs' import { Popup } from 'leaflet' import { useLocation } from 'react-router-dom'; -import { useAssetApi } from '../AppShell/hooks/useAssets' import { getValue } from '../../Utils/GetValue' +import { hashTagRegex } from '../../Utils/HashTagRegex' +import { randomColor } from '../../Utils/RandomColor' -export const Layer = ( { +export const Layer = ({ data, children, - name='places', - menuIcon='MapPinIcon', - menuText='add new place', - menuColor='#2E7D32', - markerIcon='circle-solid', - markerShape='circle', - markerDefaultColor='#777', + name = 'places', + menuIcon = 'MapPinIcon', + menuText = 'add new place', + menuColor = '#2E7D32', + markerIcon = 'circle-solid', + markerShape = 'circle', + markerDefaultColor = '#777', api, - itemTitleField='name', - itemTextField='text', + itemNameField = 'name', + itemTextField = 'text', itemAvatarField, itemColorField, itemOwnerField, + itemLatitudeField = 'position.coordinates.1', + itemLongitudeField = 'position.coordinates.0', setItemFormPopup, itemFormPopup, clusterRef @@ -47,28 +50,31 @@ export const Layer = ( { let location = useLocation(); + const allTagsLoaded = useAllTagsLoaded(); + const tags = useTags(); + const addTag = useAddTag(); + const [newTagsToAdd, setNewTagsToAdd] = useState([]); + const [tagsReady, setTagsReady] = useState(false); + const map = useMap(); const isLayerVisible = useIsLayerVisible(); - const assetsApi = useAssetApi(); - useEffect(() => { - - data && setItemsData({data, children, name, menuIcon, menuText, menuColor, markerIcon, markerShape, markerDefaultColor, api, itemTitleField, itemTextField, itemAvatarField, itemColorField, setItemFormPopup, itemFormPopup, clusterRef}); - api && setItemsApi({data, children, name, menuIcon, menuText, menuColor, markerIcon, markerShape, markerDefaultColor, api, itemTitleField, itemTextField, itemAvatarField, itemColorField, setItemFormPopup, itemFormPopup, clusterRef}); + data && setItemsData({ data, children, name, menuIcon, menuText, menuColor, markerIcon, markerShape, markerDefaultColor, api, itemNameField, itemTextField, itemAvatarField, itemColorField, itemOwnerField, setItemFormPopup, itemFormPopup, clusterRef }); + api && setItemsApi({ data, children, name, menuIcon, menuText, menuColor, markerIcon, markerShape, markerDefaultColor, api, itemNameField, itemTextField, itemAvatarField, itemColorField, itemOwnerField, setItemFormPopup, itemFormPopup, clusterRef }); }, [data, api]) useMapEvents({ popupopen: (e) => { - const item = Object.entries(leafletRefs).find(r => r[1].popup == e.popup)?.[1].item; + const item = Object.entries(leafletRefs).find(r => r[1].popup == e.popup)?.[1].item; if (item?.layer?.name == name && window.location.pathname.split("/")[2] != item.id) { window.history.pushState({}, "", `/${name}/${item.id}`) let title = ""; - if(item.name) title = item.name; - else if (item.layer?.itemTitleField) title = getValue(item, item.layer.itemTitleField); + if (item.name) title = item.name; + else if (item.layer?.itemNameField) title = getValue(item, item.layer.itemNameField); document.title = `${document.title.split("-")[0]} - ${title}`; } }, @@ -90,8 +96,8 @@ export const Layer = ( { }); const item = leafletRefs[id]?.item; let title = ""; - if(item.name) title = item.name; - else if (item.layer?.itemTitleField) title = getValue(item, item.layer.itemTitleField); + if (item.name) title = item.name; + else if (item.layer?.itemNameField) title = getValue(item, item.layer.itemNameField); document.title = `${document.title.split("-")[0]} - ${title}`; document.querySelector('meta[property="og:title"]')?.setAttribute("content", item.name); document.querySelector('meta[property="og:description"]')?.setAttribute("content", item.text); @@ -106,68 +112,102 @@ export const Layer = ( { openPopup(); }, [leafletRefs, location]) + useEffect(() => { + }, [allTagsLoaded]) + + useEffect(() => { + if(tagsReady){ + newTagsToAdd.map(newtag => { + addTag(newtag); + setNewTagsToAdd(current => + current.filter(tag => { + return tag.id !== newtag.id; + }), + ) + }) + } + }, [tagsReady]) return ( <> {items && items. - filter(item => item.text). filter(item => item.layer?.name === name)?. filter(item => - filterTags.length == 0 ? item : filterTags.every(tag => getItemTags(item).some(filterTag => filterTag.id === tag.id)))?. + filterTags.length == 0 ? item : filterTags.every(tag => getItemTags(item).some(filterTag => filterTag.id.toLocaleLowerCase() === tag.id.toLocaleLowerCase())))?. filter(item => item.layer && isLayerVisible(item.layer)). - map((item: Item) => { - const tags = getItemTags(item); + map((item: Item) => { + if (getValue(item, itemLongitudeField) && getValue(item, itemLatitudeField)) { + if (item?.tags) { + item[itemTextField] = getValue(item, itemTextField) + '\n\n'; + item.tags.map(tag => { + if(!item[itemTextField].includes(`#${tag}`)) + return (item[itemTextField] = item[itemTextField] + `#${tag} `) + return item[itemTextField] + + }); + } + if(allTagsLoaded) { + item[itemTextField].toLocaleLowerCase().match(hashTagRegex)?.map(tag=> { + if ((!tags.find((t) => t.id.toLocaleLowerCase() === tag.slice(1).toLocaleLowerCase()))&& !newTagsToAdd.find((t) => t.id.toLocaleLowerCase() === tag.slice(1).toLocaleLowerCase())) { + const newTag = {id: tag.slice(1).toLocaleLowerCase(), color: randomColor()}; + setNewTagsToAdd(current => [...current, newTag]); + } + }); + !tagsReady && setTagsReady(true); + } - let color1 = markerDefaultColor; - let color2 = "RGBA(35, 31, 32, 0.2)"; - if (itemColorField) color1 = getValue(item, itemColorField); - if(color1 == null) color1 = markerDefaultColor; - - else if (tags && tags[0]) { - color1 = tags[0].color; - } - if (tags && tags[0] && itemColorField) color2 = tags[0].color; - else if (tags && tags[1]) { - color2 = tags[1].color; - } - return ( - { - if (!(item.id in leafletRefs && leafletRefs[item.id].marker == r)) - r && addMarker(item, r); - }} icon={MarkerIconFactory(markerShape, color1, color2, markerIcon)} key={item.id} position={[item.position.coordinates[1], item.position.coordinates[0]]}> - { - (children && React.Children.toArray(children).some(child => React.isValidElement(child) && child.props.__TYPE === "ItemView") ? - React.Children.toArray(children).map((child) => - React.isValidElement(child) && child.props.__TYPE === "ItemView" ? - { + + const itemTtags = getItemTags(item); + + const latitude = itemLatitudeField && item ? getValue(item, itemLatitudeField) : undefined; + const longitude = itemLongitudeField && item ? getValue(item, itemLongitudeField) : undefined; + + let color1 = markerDefaultColor; + let color2 = "RGBA(35, 31, 32, 0.2)"; + if (itemColorField) color1 = getValue(item, itemColorField); + + else if (itemTtags && itemTtags[0]) { + color1 = itemTtags[0].color; + } + if (itemTtags && itemTtags[0] && itemColorField) color2 = itemTtags[0].color; + else if (itemTtags && itemTtags[1]) { + color2 = itemTtags[1].color; + } + return ( + { + if (!(item.id in leafletRefs && leafletRefs[item.id].marker == r)) + r && addMarker(item, r); + }} icon={MarkerIconFactory(markerShape, color1, color2, markerIcon)} key={item.id} position={[latitude, longitude]}> + { + (children && React.Children.toArray(children).some(child => React.isValidElement(child) && child.props.__TYPE === "ItemView") ? + React.Children.toArray(children).map((child) => + React.isValidElement(child) && child.props.__TYPE === "ItemView" ? + { + if (!(item.id in leafletRefs && leafletRefs[item.id].popup == r)) + r && addPopup(item, r as Popup); + }} key={item.id + item.name} + item={item} + setItemFormPopup={setItemFormPopup}> + {child} + + : "" + ) + : + <> + { if (!(item.id in leafletRefs && leafletRefs[item.id].popup == r)) r && addPopup(item, r as Popup); - }} key={item.id + item.name} - title={itemTitleField && item ? getValue(item, itemTitleField) : undefined} - avatar={itemAvatarField && item && getValue(item, itemAvatarField)? assetsApi.url + getValue(item, itemAvatarField) : undefined} - owner={itemOwnerField && item ? getValue(item, itemOwnerField) : undefined} + }} item={item} - setItemFormPopup={setItemFormPopup}> - {child} - - : "" - ) - : - <> - { - if (!(item.id in leafletRefs && leafletRefs[item.id].popup == r)) - r && addPopup(item, r as Popup); - }} title={itemTitleField && item ? getValue(item, itemTitleField) : undefined} - avatar={itemAvatarField && item && getValue(item, itemAvatarField)? assetsApi.url + getValue(item, itemAvatarField) : undefined} - owner={itemOwnerField && item ? getValue(item, itemOwnerField) : undefined} - item={item} - setItemFormPopup={setItemFormPopup} /> - ) - } - {item.name? item.name : getValue(item, itemTitleField)} - - ); + setItemFormPopup={setItemFormPopup} /> + ) + } + {item.name ? item.name : getValue(item, itemNameField)} + + ); + } + else return null; }) } {//{children}} diff --git a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx index 3adba36a..5042ea65 100644 --- a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx +++ b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx @@ -47,7 +47,8 @@ export const SearchControl = ({ clusterRef }) => { }; searchGeo(); setItemsResults(items.filter(item => { - if (item.layer?.itemTitleField) item.name = getValue(item, item.layer.itemTitleField) + if (item.layer?.itemNameField) item.name = getValue(item, item.layer.itemNameField) + if (item.layer?.itemTextField) item.text = getValue(item, item.layer.itemTextField) return item.name?.toLowerCase().includes(value.toLowerCase()) || item.text?.toLowerCase().includes(value.toLowerCase()) })) setTagsResults(tags.filter(tag => tag.id?.toLowerCase().includes(value.toLowerCase()))) diff --git a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx index 4a293bdb..ebeb0cbb 100644 --- a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx +++ b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx @@ -7,14 +7,14 @@ import { Item } from "../../../../types"; import { toast } from "react-toastify"; import { useHasUserPermission } from "../../hooks/usePermissions"; import { useAuth } from "../../../Auth"; +import { getValue } from "../../../../Utils/GetValue"; +import { useAssetApi } from '../../../AppShell/hooks/useAssets' -export function HeaderView({ item, title, avatar, owner, setItemFormPopup }: { + +export function HeaderView({ item, setItemFormPopup }: { item: Item, - title?: string, - avatar?: string, - owner?: string, setItemFormPopup?: React.Dispatch> }) { @@ -26,6 +26,13 @@ export function HeaderView({ item, title, avatar, owner, setItemFormPopup }: { const { user } = useAuth(); + const assetsApi = useAssetApi(); + + const avatar = item.layer?.itemAvatarField && item && getValue(item, item.layer?.itemAvatarField)? assetsApi.url + getValue(item, item.layer?.itemAvatarField ) : undefined; + const title = item.layer?.itemNameField && item ? getValue(item, item.layer?.itemNameField) : undefined; + const owner = item.layer?.itemOwnerField && item ? getValue(item, item.layer?.itemOwnerField) : undefined; + + const removeItemFromMap = async (event: React.MouseEvent) => { setLoading(true); diff --git a/src/Components/Map/Subcomponents/ItemPopupComponents/TextView.tsx b/src/Components/Map/Subcomponents/ItemPopupComponents/TextView.tsx index 24efd282..ab2d5a81 100644 --- a/src/Components/Map/Subcomponents/ItemPopupComponents/TextView.tsx +++ b/src/Components/Map/Subcomponents/ItemPopupComponents/TextView.tsx @@ -6,14 +6,17 @@ import { hashTagRegex } from '../../../../Utils/HashTagRegex'; import { fixUrls, mailRegex } from '../../../../Utils/ReplaceURLs'; import Markdown from 'react-markdown' import rehypeVideo from 'rehype-video'; +import { getValue } from '../../../../Utils/GetValue'; export const TextView = ({ item }: { item?: Item }) => { const tags = useTags(); const addFilterTag = useAddFilterTag(); + const text = item?.layer?.itemTextField && item ? getValue(item, item.layer?.itemTextField) : undefined; + let replacedText; - if (item && item.text) replacedText = fixUrls(item.text); + if (item && text) replacedText = fixUrls(text); replacedText = replacedText.replace(/(? { let shortUrl = url; @@ -63,6 +66,9 @@ export const TextView = ({ item }: { item?: Item }) => { const CustomOrderdList = ({ children }) => (
    {children}
); + const CustomHorizontalRow = ({ children }) => ( +
{children} + ); const CustomImage = ({ alt, src, title }) => ( { {children} ); - const CustomHashTagLink = ({ children, tag, item }) => ( + const CustomHashTagLink = ({ children, tag, item }) => { + return ( { + onClick={(e) => { e.stopPropagation(); addFilterTag(tag!); // map.fitBounds(items) // map.closePopup(); }}>{children} - ); - - const isSpecialYouTubeLink = (url) => { - return /(?<=!\()[^)]+(?=\))/g.test(url); - }; - + )}; return ( //@ts-ignore @@ -111,15 +113,15 @@ export const TextView = ({ item }: { item?: Item }) => { return ( -