diff --git a/src/Components/Map/Layer.tsx b/src/Components/Map/Layer.tsx index 4ba80c06..435358f9 100644 --- a/src/Components/Map/Layer.tsx +++ b/src/Components/Map/Layer.tsx @@ -3,13 +3,15 @@ import { Marker } from 'react-leaflet' import { Item, Tag, Layer as LayerProps } from '../../types' import MarkerIconFactory from '../../Utils/MarkerIconFactory' import { Popup } from './Subcomponents/Popup' -import { useLayers, useAddLayer } from './hooks/useLayers' import { useTags } from './hooks/useTags' +import { useAddItem, useItems } from './hooks/useItems' +import { useEffect } from 'react' +import { useAddLayer } from './hooks/useLayers' export const Layer = (props: LayerProps) => { - const tags = useTags(); - + const tags = useTags(); + // create a JS-Map with all Tags let tagMap = new Map(tags?.map(key => [key.id, key])); @@ -22,28 +24,36 @@ export const Layer = (props: LayerProps) => { return tags; }; + const items = useItems(); + const addItem = useAddItem() const addLayer = useAddLayer(); + + useEffect(() => { + props.data.map(item => { + item.layer = props; + addItem(item); + }) + }, []) addLayer(props); - const layers = useLayers(); - + return ( <> - {layers.get(props.name)?.data?.map((place: Item) => { - let tags = getTags(place); - let color1 = "#666"; - let color2 = "RGBA(35, 31, 32, 0.2)"; - if (tags[0]) { - color1 = tags[0].color; - } - if (tags[1]) { - color2 = tags[1].color; - } - return ( - - - - ); - }) + {items.filter(item => item.layer?.name === props.name)?.map((place: Item) => { + let tags = getTags(place); + let color1 = "#666"; + let color2 = "RGBA(35, 31, 32, 0.2)"; + if (tags[0]) { + color1 = tags[0].color; + } + if (tags[1]) { + color2 = tags[1].color; + } + return ( + + + + ); + }) } {props.children} diff --git a/src/Components/Map/Subcomponents/AddButton.tsx b/src/Components/Map/Subcomponents/AddButton.tsx index ff211d0a..afbb7855 100644 --- a/src/Components/Map/Subcomponents/AddButton.tsx +++ b/src/Components/Map/Subcomponents/AddButton.tsx @@ -6,6 +6,8 @@ import { useLayers } from '../hooks/useLayers' export default function AddButton({setSelectMode} : {setSelectMode: React.Dispatch>}) { const layers = useLayers(); + console.log(layers); + console.log(useLayers()); return (
@@ -16,9 +18,8 @@ export default function AddButton({setSelectMode} : {setSelectMode: React.Dispat C15.952,9,16,9.447,16,10z" /> - {layers && - } +
) } diff --git a/src/Components/Map/Subcomponents/NewItemPopup.tsx b/src/Components/Map/Subcomponents/NewItemPopup.tsx index 81753fdd..4c16e1b8 100644 --- a/src/Components/Map/Subcomponents/NewItemPopup.tsx +++ b/src/Components/Map/Subcomponents/NewItemPopup.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { LatLng } from 'leaflet' import { Popup as LeafletPopup, useMap } from 'react-leaflet' import { useState } from 'react' -import { useAddItem } from '../hooks/useLayers' +import { useAddItem } from '../hooks/useItems' import { Geometry, Layer, Item} from '../../../types' export interface NewItemPopupProps { @@ -22,7 +22,7 @@ export default function NewItemPopup(props: NewItemPopupProps) { evt.preventDefault() console.log("New Item Popup is adding Item ..."); - addItem(new Item(Math.floor(Math.random() * 1000) + 200, name, text, new Geometry(props.position.lng, props.position.lat)), props.layer) + addItem(new Item(Math.floor(Math.random() * 1000) + 200, name, text, new Geometry(props.position.lng, props.position.lat), props.layer)) map.closePopup(); props.setNewItemPopup(null); diff --git a/src/Components/Map/Subcomponents/Popup.tsx b/src/Components/Map/Subcomponents/Popup.tsx index b225fc61..1dd1de89 100644 --- a/src/Components/Map/Subcomponents/Popup.tsx +++ b/src/Components/Map/Subcomponents/Popup.tsx @@ -1,20 +1,59 @@ import * as React from 'react' -import { Popup as LeafletPopup} from 'react-leaflet' +import { Popup as LeafletPopup, useMap } from 'react-leaflet' import { Item, Tag } from '../../../types' import { replaceURLs } from '../../../Utils/ReplaceURLs' +import { useRemoveItem } from '../hooks/useItems' export interface UtopiaPopupProps { item: Item, - tags: Tag[] + tags: Tag[], } + const Popup = (props: UtopiaPopupProps) => { const item: Item = props.item; const tags: Tag[] = props.tags; + const removeItem = useRemoveItem(); + const map = useMap(); + + const removeItemFromMap = (event: React.MouseEvent) => { + removeItem(item) + event.stopPropagation() + map.closePopup(); + } return ( - {item.name} +
+
+ {item.name} +
+
+
+ + +
+
+
{item.start && item.end &&
@@ -48,6 +87,6 @@ const Popup = (props: UtopiaPopupProps) => { ) } -export {Popup}; +export { Popup }; diff --git a/src/Components/Map/Tags.tsx b/src/Components/Map/Tags.tsx index 081f0b71..b983cdda 100644 --- a/src/Components/Map/Tags.tsx +++ b/src/Components/Map/Tags.tsx @@ -5,11 +5,8 @@ import { useAddTag } from './hooks/useTags' export function Tags({data} : {data: Tag[]}) { const addTag = useAddTag(); - - useEffect(() => { data.map(tag => { - console.log("Tag added: " + tag.name); addTag(tag) }) }, []) diff --git a/src/Components/Map/UtopiaMap.tsx b/src/Components/Map/UtopiaMap.tsx index 7d1de0f1..d4b89038 100644 --- a/src/Components/Map/UtopiaMap.tsx +++ b/src/Components/Map/UtopiaMap.tsx @@ -8,10 +8,9 @@ import MarkerClusterGroup from 'react-leaflet-cluster' import AddButton from "./Subcomponents/AddButton"; import { useState } from "react"; import NewItemPopup, { NewItemPopupProps } from "./Subcomponents/NewItemPopup"; -import { LayersProvider } from "./hooks/useLayers"; +import { ItemsProvider } from "./hooks/useItems"; import { TagsProvider } from "./hooks/useTags"; - - +import { LayersProvider } from "./hooks/useLayers"; export interface MapEventListenerProps { selectMode: Layer | null, @@ -46,35 +45,38 @@ function UtopiaMap({ const [newItemPopup, setNewItemPopup] = useState(null); return ( - - -
- - - - {children} - - - {newItemPopup && - - } - - - {selectMode != null && -
-
-
- Select {selectMode.name} position! + + + +
+ + + + {children} + + + {newItemPopup && + + } + + + {selectMode != null && +
+
+
+ Select {selectMode.name} position! +
-
- } + } + +
+ + + -
- - ); } diff --git a/src/Components/Map/data.ts b/src/Components/Map/data.ts index c44f1b21..71991a11 100644 --- a/src/Components/Map/data.ts +++ b/src/Components/Map/data.ts @@ -70,7 +70,24 @@ export const events : Item[] = [ "end": "2022-10-08T12:00:00", "tags": [5,6,11], - } + }, + + { + "id": 247, + "name": "anderes Event", + "text": "Zu den Vollmonden vom März bis Oktober treffen sich traditionell Menschen zum gemeinsamen Musizieren, Tanzen, Spielen, Grillen und Entspannen am Gerloser Häuschen im Niesiger Wald.\r\n\r\nUhrzeit: immer ab 17 Uhr\r\n\r\nhttps://trommeln-fulda.de/vollmondtrommeln/", + "position": { + "type": "Point", + "coordinates": [ + 9.67, + 50.589 + ] + }, + "start": "2022-03-18T12:00:00", + "end": "2022-10-08T12:00:00", + "tags": [5,6,11], + +} ]; export const places : Item[] = [ diff --git a/src/Components/Map/hooks/useItems.tsx b/src/Components/Map/hooks/useItems.tsx new file mode 100644 index 00000000..98fa20d9 --- /dev/null +++ b/src/Components/Map/hooks/useItems.tsx @@ -0,0 +1,73 @@ +import { useCallback, useReducer, createContext, useContext } from "react"; +import * as React from "react"; +import { Item } from "../../../types"; + +type ActionType = +| { type: "ADD"; item: Item } +| { type: "REMOVE"; item: Item }; + +type UseItemManagerResult = ReturnType; + +const ItemContext = createContext({ + items: [], + addItem: () => {}, + removeItem: () => {} +}); + +function useItemsManager (initialItems: Item[]): { + items: Item[]; + addItem: (item: Item) => void; + removeItem: (item: Item) => void; +} { + const [items, dispatch] = useReducer((state: Item[], action: ActionType) => { + switch (action.type) { + case "ADD": + return [ + ...state, + action.item, + ]; + case "REMOVE": + return state.filter(item => item !== action.item); + default: + throw new Error(); + } + }, initialItems); + + const addItem = useCallback((item: Item) => { + dispatch({ + type: "ADD", + item, + }); + }, []); + + const removeItem = useCallback((item: Item) => { + dispatch({ + type: "REMOVE", + item, + }); + }, []); + return { items, addItem, removeItem }; +} + +export const ItemsProvider: React.FunctionComponent<{ + initialItems: Item[], children?: React.ReactNode +}> = ({ initialItems, children }) => ( + + {children} + +); + +export const useItems = (): Item[] => { + const { items } = useContext(ItemContext); + return items; +}; + +export const useAddItem = (): UseItemManagerResult["addItem"] => { + const { addItem } = useContext(ItemContext); + return addItem; +}; + +export const useRemoveItem = (): UseItemManagerResult["removeItem"] => { + const { removeItem } = useContext(ItemContext); + return removeItem; +}; \ No newline at end of file diff --git a/src/Components/Map/hooks/useLayers.tsx b/src/Components/Map/hooks/useLayers.tsx index d14eb6ac..7a10c9ac 100644 --- a/src/Components/Map/hooks/useLayers.tsx +++ b/src/Components/Map/hooks/useLayers.tsx @@ -4,37 +4,33 @@ import { Item, Layer } from "../../../types"; type ActionType = | { type: "ADD LAYER"; layer: Layer } - | { type: "ADD ITEM"; item: Item; layer: Layer } - | { type: "REMOVE ITEM"; id: number; layer: Layer }; + | { type: "ADD ITEM"; item: Item; layer: Layer }; type UseItemManagerResult = ReturnType; const LayerContext = createContext({ - layers: new Map([]), + layers: [], addLayer: () => { }, - addItem: () => { }, - removeItem: () => { } }); -function useLayerManager(initialLayers: Map): { - layers: Map; +function useLayerManager(initialLayers: Layer[]): { + layers: Layer[]; addLayer: (layer: Layer) => void; - addItem: (item: Item, layer: Layer) => void; - removeItem: (id: number, layer: Layer) => void; } { - const [layers, dispatch] = useReducer((state: Map, action: ActionType) => { + const [layers, dispatch] = useReducer((state: Layer[], action: ActionType) => { switch (action.type) { case "ADD LAYER": { - return state.set(action.layer.name, action.layer); + if (!state.includes(action.layer)) + state.push(action.layer); + return state; } case "ADD ITEM": { - if(!state.get(action.layer.name)?.data?.includes(action.item)) - state.get(action.layer.name)?.data?.push(action.item); + if(!state.find(layer => layer.name === action.layer.name)?.data.find(item => item.id === action.item.id)) + state.find(layer => layer.name === action.layer.name)?.data.push(action.item) + return state; } - case "REMOVE ITEM": - { return state; } default: throw new Error(); } @@ -47,33 +43,18 @@ function useLayerManager(initialLayers: Map): { }); }, []); - const addItem = useCallback((item: Item, layer: Layer) => { - dispatch({ - type: "ADD ITEM", - item, - layer - }); - }, []); - - const removeItem = useCallback((id: number, layer: Layer) => { - dispatch({ - type: "REMOVE ITEM", - id, - layer - }); - }, []); - return { layers, addLayer, addItem, removeItem }; + return { layers, addLayer}; } export const LayersProvider: React.FunctionComponent<{ - initialLayers: Map, children?: React.ReactNode + initialLayers: Layer[], children?: React.ReactNode }> = ({ initialLayers, children }) => ( {children} ); -export const useLayers = (): Map => { +export const useLayers = (): Layer[] => { const { layers } = useContext(LayerContext); return layers; }; @@ -82,13 +63,3 @@ export const useAddLayer = (): UseItemManagerResult["addLayer"] => { const { addLayer } = useContext(LayerContext); return addLayer; }; - -export const useAddItem = (): UseItemManagerResult["addItem"] => { - const { addItem } = useContext(LayerContext); - return addItem; -}; - -export const useRemoveItem = (): UseItemManagerResult["removeItem"] => { - const { removeItem } = useContext(LayerContext); - return removeItem; -}; diff --git a/src/types.ts b/src/types.ts index 1258da65..07b85be0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -11,7 +11,7 @@ export interface UtopiaMap { } export interface Layer { - data?: Item[], + data: Item[], children?: React.ReactNode name: string, menuIcon: string, @@ -20,7 +20,7 @@ export interface Layer { markerIcon: string, markerShape: string, markerDefaultColor: string, - tags?: Tag[] + tags?: Tag[], } export class Item { @@ -30,15 +30,16 @@ export class Item { name: string; text: string; position: Geometry; + layer?: Layer; start?: string; end?: string; tags?: number[]; - [key: string]: any; - constructor(id:number,name:string,text:string,position:Geometry){ + constructor(id:number,name:string,text:string,position:Geometry, layer: Layer){ this.id = id; this.name = name; this.text = text; this.position = position; + this.layer = layer; } } @@ -60,4 +61,6 @@ export interface Tag { export interface API { getAll(): Promise, add(item : Item): Promise, + update(item : Item): Promise, + remove(id : number): Promise, } \ No newline at end of file