{props.children ?
diff --git a/src/Components/Map/UtopiaMap.tsx b/src/Components/Map/UtopiaMap.tsx
index 697691ef..89bf2ce2 100644
--- a/src/Components/Map/UtopiaMap.tsx
+++ b/src/Components/Map/UtopiaMap.tsx
@@ -14,9 +14,10 @@ import { QuestControl } from "./Subcomponents/Controls/QuestControl";
import { Control } from "./Subcomponents/Controls/Control";
import { Outlet, useLocation, useNavigate } from "react-router-dom";
import { TagsControl } from "./Subcomponents/Controls/TagsControl";
-import { useSelectPosition, useSetSelectPosition } from "./hooks/useSetItemPosition";
+import { useSelectPosition, useSetSelectPosition } from "./hooks/useSelectPosition";
import { useUpdateItem } from "./hooks/useItems";
import { toast } from "react-toastify";
+import { useClusterRef, useSetClusterRef } from "./hooks/useClusterRef";
export interface MapEventListenerProps {
@@ -44,15 +45,14 @@ function UtopiaMap({
window.history.pushState({}, "", `/` + `${params.toString() !== "" ? `?${params}` : ""}`)
document.title = document.title.split("-")[0];
document.querySelector('meta[property="og:title"]')?.setAttribute("content", document.title);
- document.querySelector('meta[property="og:description"]')?.setAttribute("content", `${document.querySelector('meta[name="description"]')?.getAttribute("content")}`);
-
+ document.querySelector('meta[property="og:description"]')?.setAttribute("content", `${document.querySelector('meta[name="description"]')?.getAttribute("content")}`);
console.log(e.latlng.lat + ',' + e.latlng.lng);
if (selectNewItemPosition != null) {
if ('menuIcon' in selectNewItemPosition) {
props.setItemFormPopup({ layer: props.selectNewItemPosition, position: e.latlng })
props.setSelectNewItemPosition(null)
}
- if ('position' in selectNewItemPosition) {
+ if ('text' in selectNewItemPosition) {
const position = new Geometry(e.latlng.lng,e.latlng.lat);
itemUpdate({...selectNewItemPosition as Item, position: position })
setSelectNewItemPosition(null);
@@ -61,14 +61,13 @@ function UtopiaMap({
},
moveend: (e) => {
console.log(e);
- }
+ },
+
})
return null
}
const itemUpdate = async (updatedItem: Item) => {
- console.log(updatedItem);
- console.log(updatedItem?.layer?.api?.updateItem!);
let success = false;
try {
await updatedItem?.layer?.api?.updateItem!({id: updatedItem.id, position: updatedItem.position })
@@ -85,10 +84,11 @@ function UtopiaMap({
const selectNewItemPosition = useSelectPosition();
const setSelectNewItemPosition = useSetSelectPosition();
- const clusterRef = React.useRef();
const location = useLocation();
const updateItem = useUpdateItem();
const navigate = useNavigate();
+ const setClusterRef = useSetClusterRef();
+ const clusterRef = useClusterRef();
const [itemFormPopup, setItemFormPopup] = useState
(null);
@@ -100,13 +100,11 @@ function UtopiaMap({
return (
<>
-
-
-
+
@@ -117,7 +115,7 @@ function UtopiaMap({
maxZoom={19}
attribution='© OpenStreetMap contributors'
url="https://tile.osmand.net/hd/{z}/{x}/{y}.png" />
-
+ setClusterRef(r)} showCoverageOnHover chunkedLoading maxClusterRadius={50} removeOutsideVisibleBounds={false}>
{
React.Children.toArray(children).map((child) =>
React.isValidElement<{ setItemFormPopup: React.Dispatch>, itemFormPopup: ItemFormPopupProps | null, clusterRef: React.MutableRefObject }>(child) ?
diff --git a/src/Components/Map/hooks/useClusterRef.tsx b/src/Components/Map/hooks/useClusterRef.tsx
new file mode 100644
index 00000000..e4f83b98
--- /dev/null
+++ b/src/Components/Map/hooks/useClusterRef.tsx
@@ -0,0 +1,40 @@
+import { createContext, useContext, useState } from "react";
+
+type UseClusterRefManagerResult = ReturnType;
+
+const ClusterRefContext = createContext({
+ clusterRef: {} as React.MutableRefObject,
+ setClusterRef: () => { },
+});
+
+function useClusterRefManager(): {
+ clusterRef: any
+ setClusterRef: React.Dispatch>>;
+} {
+ const [clusterRef, setClusterRef] = useState>({} as React.MutableRefObject);
+
+ return { clusterRef, setClusterRef };
+
+}
+
+
+
+
+export const ClusterRefProvider: React.FunctionComponent<{
+ children?: React.ReactNode
+}> = ({ children }) => (
+
+ {children}
+
+);
+
+export const useClusterRef = (): any=> {
+ const { clusterRef } = useContext(ClusterRefContext);
+ return clusterRef;
+};
+
+export const useSetClusterRef = (): UseClusterRefManagerResult["setClusterRef"] => {
+ const { setClusterRef } = useContext(ClusterRefContext);
+ return setClusterRef;
+}
+
diff --git a/src/Components/Map/hooks/useSelectPosition.tsx b/src/Components/Map/hooks/useSelectPosition.tsx
new file mode 100644
index 00000000..f4d59d9a
--- /dev/null
+++ b/src/Components/Map/hooks/useSelectPosition.tsx
@@ -0,0 +1,107 @@
+import { createContext, useContext, useEffect, useState } from "react";
+import { Item, LayerProps } from '../../../types';
+import { useUpdateItem } from "./useItems";
+import { toast } from "react-toastify";
+import { useHasUserPermission } from "./usePermissions";
+
+type UseSelectPositionManagerResult = ReturnType;
+
+const SelectPositionContext = createContext({
+ selectPosition: null,
+ setSelectPosition: () => { },
+ setMarkerClicked: () => { },
+});
+
+function useSelectPositionManager(): {
+ selectPosition: Item | LayerProps | null;
+ setSelectPosition: React.Dispatch>;
+ setMarkerClicked: React.Dispatch>;
+} {
+ const [selectPosition, setSelectPosition] = useState(null);
+ const [markerClicked, setMarkerClicked] = useState- ();
+ const updateItem = useUpdateItem();
+ const hasUserPermission = useHasUserPermission();
+
+
+ useEffect(() => {
+ if (selectPosition && markerClicked && 'text' in selectPosition) {
+ itemUpdate({ ...selectPosition, parent: markerClicked.id })
+ }
+ }, [markerClicked])
+
+ const itemUpdate = async (updatedItem: Item) => {
+ if (markerClicked?.layer?.api?.collectionName && hasUserPermission(markerClicked?.layer?.api?.collectionName, "update", markerClicked)) {
+ let success = false;
+ try {
+ await updatedItem?.layer?.api?.updateItem!({ id: updatedItem.id, parent: updatedItem.parent, position: null })
+ success = true;
+ } catch (error) {
+ toast.error(error.toString());
+ }
+ if (success) {
+ await updateItem({ ...updatedItem, parent: updatedItem.parent, position: undefined })
+ await linkItem(updatedItem.id);
+ toast.success("Item position updated");
+ setSelectPosition(null);
+ }
+ }
+ else {
+ setSelectPosition(null);
+ toast.error("you don't have permission to add items to " + markerClicked?.name);
+ }
+
+ }
+
+ const linkItem = async (id: string) => {
+ if (markerClicked) {
+ let new_relations = markerClicked.relations || [];
+ console.log(new_relations);
+ console.log(id);
+
+
+ if (!new_relations.some(r => r.related_items_id == id)) {
+ new_relations?.push({ items_id: markerClicked.id, related_items_id: id })
+ const updatedItem = { id: markerClicked.id, relations: new_relations }
+
+ let success = false;
+ try {
+ await markerClicked?.layer?.api?.updateItem!(updatedItem)
+ success = true;
+ } catch (error) {
+ toast.error(error.toString());
+ }
+ if (success) {
+ updateItem({ ...markerClicked, relations: new_relations })
+ toast.success("Item linked");
+ }
+ }
+ }
+ }
+ return { selectPosition, setSelectPosition, setMarkerClicked };
+}
+
+
+
+
+export const SelectPositionProvider: React.FunctionComponent<{
+ children?: React.ReactNode
+}> = ({ children }) => (
+
+ {children}
+
+);
+
+export const useSelectPosition = (): Item | LayerProps | null => {
+ const { selectPosition } = useContext(SelectPositionContext);
+ return selectPosition;
+};
+
+export const useSetSelectPosition = (): UseSelectPositionManagerResult["setSelectPosition"] => {
+ const { setSelectPosition } = useContext(SelectPositionContext);
+ return setSelectPosition;
+}
+
+export const useSetMarkerClicked = (): UseSelectPositionManagerResult["setMarkerClicked"] => {
+ const { setMarkerClicked } = useContext(SelectPositionContext);
+ return setMarkerClicked;
+}
\ No newline at end of file
diff --git a/src/Components/Map/hooks/useSetItemPosition.tsx b/src/Components/Map/hooks/useSetItemPosition.tsx
deleted file mode 100644
index d0f86219..00000000
--- a/src/Components/Map/hooks/useSetItemPosition.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { createContext, useContext, useState } from "react";
-import { Item, LayerProps } from '../../../types';
-
-type UseSelectPositionManagerResult = ReturnType;
-
-const SelectPositionContext = createContext({
- selectPosition: null,
- setSelectPosition: () => { },
-});
-
-function useSelectPositionManager(): {
- selectPosition: Item | LayerProps | null;
- setSelectPosition: React.Dispatch>;
-} {
- const [selectPosition, setSelectPosition] = useState(null);
- return { selectPosition, setSelectPosition };
-}
-
-export const SelectPositionProvider: React.FunctionComponent<{
- children?: React.ReactNode
-}> = ({ children }) => (
-
- {children}
-
-);
-
-export const useSelectPosition = (): Item | LayerProps | null => {
- const { selectPosition } = useContext(SelectPositionContext);
- return selectPosition;
-};
-
-export const useSetSelectPosition = (): UseSelectPositionManagerResult["setSelectPosition"] => {
- const { setSelectPosition } = useContext(SelectPositionContext);
- return setSelectPosition;
-}
\ No newline at end of file
diff --git a/src/Components/Profile/OverlayItemProfile.tsx b/src/Components/Profile/OverlayItemProfile.tsx
index a138af3a..f2424cea 100644
--- a/src/Components/Profile/OverlayItemProfile.tsx
+++ b/src/Components/Profile/OverlayItemProfile.tsx
@@ -8,7 +8,7 @@ import { LatLng } from 'leaflet';
import { PopupStartEndInput, StartEndView, TextView } from '../Map';
import useWindowDimensions from '../Map/hooks/useWindowDimension';
import { useAddTag, useTags } from '../Map/hooks/useTags';
-import { useResetFilterTags } from '../Map/hooks/useFilter';
+import { useFilterTags, useResetFilterTags } from '../Map/hooks/useFilter';
import { useHasUserPermission } from '../Map/hooks/usePermissions';
import { TextAreaInput, TextInput } from '../Input';
import { hashTagRegex } from '../../Utils/HashTagRegex';
@@ -19,44 +19,38 @@ import { useLayers } from '../Map/hooks/useLayers';
import { ActionButton } from './ActionsButton';
import { LinkedItemsHeaderView } from './LinkedItemsHeaderView';
import { HeaderView } from '../Map/Subcomponents/ItemPopupComponents/HeaderView';
-import { useSelectPosition } from '../Map/hooks/useSetItemPosition';
+import { useSelectPosition, useSetSelectPosition } from '../Map/hooks/useSelectPosition';
+import { useClusterRef } from '../Map/hooks/useClusterRef';
import { useLeafletRefs } from '../Map/hooks/useLeafletRefs';
export function OverlayItemProfile() {
+ const [updatePermission, setUpdatePermission] = useState(false);
+ const [relations, setRelations] = useState>([]);
+ const [activeTab, setActiveTab] = useState(1);
+ const [addItemPopupType, setAddItemPopupType] = useState("");
+ const [loading, setLoading] = useState(false);
+
const location = useLocation();
const items = useItems();
const updateItem = useUpdateItem();
const [item, setItem] = useState
- ({} as Item)
const map = useMap();
const windowDimension = useWindowDimensions();
-
- const [updatePermission, setUpdatePermission] = useState(false);
-
const layers = useLayers();
const selectPosition = useSelectPosition();
-
const removeItem = useRemoveItem();
-
const tags = useTags();
-
const navigate = useNavigate();
-
- const [relations, setRelations] = useState>([]);
-
- const [activeTab, setActiveTab] = useState(1);
-
- const [addItemPopupType, setAddItemPopupType] = useState("");
-
- const [loading, setLoading] = useState(false);
-
const addTag = useAddTag();
const resetFilterTags = useResetFilterTags();
-
+ const filterTags = useFilterTags();
const addItem = useAddItem();
const { user } = useAuth();
-
const hasUserPermission = useHasUserPermission();
+ const setSelectPosition = useSetSelectPosition();
+ const clusterRef = useClusterRef();
+ const leafletRefs = useLeafletRefs();
const tabRef = useRef(null);
@@ -68,11 +62,6 @@ export function OverlayItemProfile() {
scroll();
}, [addItemPopupType])
- useEffect(() => {
- console.log(addItemPopupType);
-
- }, [addItemPopupType])
-
const updateActiveTab = (id: number) => {
setActiveTab(id);
@@ -85,18 +74,31 @@ export function OverlayItemProfile() {
}
useEffect(() => {
-
const itemId = location.pathname.split("/")[2];
const item = items.find(i => i.id === itemId);
item && setItem(item);
- const bounds = map.getBounds();
- const x = bounds.getEast() - bounds.getWest()
- if (windowDimension.width > 768)
- if (item?.position && item?.position.coordinates[0])
- map.setView(new LatLng(item?.position.coordinates[1]!, item?.position.coordinates[0]! + x / 4))
+ resetFilterTags();
+ if (item && filterTags.length == 0) {
+ if(item.position) {
+ const marker = Object.entries(leafletRefs).find(r => r[1].item == item)?.[1].marker;
+ marker && clusterRef?.zoomToShowLayer(marker, () => {
+ const bounds = map.getBounds();
+ const x = bounds.getEast() - bounds.getWest()
+ map.setView(new LatLng(item?.position?.coordinates[1]!, item?.position?.coordinates[0]! + x / 4), undefined, {duration: 1})}
+ );
+ }
+ else {
+ const parent = items.find(i => i.id == item.parent);
+ const marker = Object.entries(leafletRefs).find(r => r[1].item == parent)?.[1].marker;
+ marker && clusterRef?.zoomToShowLayer(marker, () => {
+ const bounds = map.getBounds();
+ const x = bounds.getEast() - bounds.getWest()
+ map.setView(new LatLng(parent?.position?.coordinates[1]!, parent?.position?.coordinates[0]! + x / 4), undefined, {duration: 1})}
+ );
+ }
+ }
-
- }, [location, items, activeTab])
+ }, [items, activeTab, leafletRefs])
useEffect(() => {
@@ -121,8 +123,6 @@ export function OverlayItemProfile() {
}, [item])
- const [selecting, setSelecting] = useState(false);
-
useEffect(() => {
selectPosition && map.closePopup();
}, [selectPosition])
@@ -233,17 +233,13 @@ export function OverlayItemProfile() {
return (
<>
- {item &&
+ {item &&
<>
- navigate("/edit-item/" + item.id)} big updatePosition/>
-
-
-
+ navigate("/edit-item/" + item.id)} setPositionCallback={()=>{map.closePopup();setSelectPosition(item); navigate("/")}} big />
-
updateActiveTab(1)} />
diff --git a/src/types.ts b/src/types.ts
index bf764f5e..3beff9b3 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -21,6 +21,7 @@ export interface LayerProps {
markerShape: string,
markerDefaultColor: string,
api?: ItemsApi
,
+ itemType: string,
itemNameField?: string,
itemTextField?: string,
itemAvatarField?: string,
@@ -35,7 +36,7 @@ export interface LayerProps {
customEditLink?: string,
setItemFormPopup?: React.Dispatch>,
itemFormPopup?: ItemFormPopupProps | null,
- clusterRef?: React.MutableRefObject
+ clusterRef?: any
}
export class Item {
@@ -51,6 +52,7 @@ export class Item {
tags?: string[];
layer?: LayerProps;
relations?: Relation[];
+ parent?:string;
[key: string]: any;
constructor(id:string,name:string,text:string,position:Geometry, layer?: LayerProps, api?: ItemsApi){
this.id = id;