update Items

This commit is contained in:
AT 2022-09-27 12:36:41 +02:00
parent 3f540ff2d4
commit de929beb45
9 changed files with 89 additions and 35 deletions

View File

@ -1,6 +1,6 @@
{
"name": "utopia-ui",
"version": "1.0.7",
"version": "1.0.8",
"description": "Reuseable React Components to build mapping apps for all kinds of communities ",
"repository": "https://github.com/utopia-os/utopia-ui",
"homepage:": "https://utopia.os/",

View File

@ -33,8 +33,10 @@ export const Layer = (props: LayerProps) => {
item.layer = props;
addItem(item);
})
addLayer(props);
}, [])
addLayer(props);
return (
<>
@ -50,7 +52,7 @@ export const Layer = (props: LayerProps) => {
}
return (
<Marker icon={MarkerIconFactory(props.markerShape, color1, color2, props.markerIcon)} key={place.id} position={[place.position.coordinates[1], place.position.coordinates[0]]}>
<Popup item={place} tags={tags} />
<Popup item={place} tags={tags} setNewItemPopup={props.setNewItemPopup}/>
</Marker>
);
})

View File

@ -6,8 +6,7 @@ import { useLayers } from '../hooks/useLayers'
export default function AddButton({setSelectMode} : {setSelectMode: React.Dispatch<React.SetStateAction<any>>}) {
const layers = useLayers();
console.log(layers);
console.log(useLayers());
console.log("Layers: " +layers);
return (
<div className="dropdown dropdown-top dropdown-end dropdown-hover z-500 absolute right-5 bottom-5" >

View File

@ -1,13 +1,14 @@
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/useItems'
import { useEffect, useState } from 'react'
import { useAddItem, useUpdateItem } from '../hooks/useItems'
import { Geometry, Layer, Item} from '../../../types'
export interface NewItemPopupProps {
position: LatLng,
layer: Layer,
item?: Item,
setNewItemPopup: React.Dispatch<React.SetStateAction<any>>
}
@ -17,22 +18,42 @@ export default function NewItemPopup(props: NewItemPopupProps) {
const map = useMap();
const addItem = useAddItem();
const updateItem = useUpdateItem();
const handleSubmit = (evt: any) => {
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))
if(props.item) {
updateItem(new Item(props.item.id, name, text, new Geometry(props.position.lng, props.position.lat), props.layer))
}
else {
addItem(new Item(crypto.randomUUID(), name, text, new Geometry(props.position.lng, props.position.lat), props.layer))}
map.closePopup();
props.setNewItemPopup(null);
}
const resetPopup = () => {
setName('');
setText('');
}
console.log("popup opend");
const setItemValues = () => {
if(props.item) {
setName(props.item?.name);
setText(props.item?.text);
console.log('set name + txt');
}
}
useEffect(() => {
setItemValues();
},[props.item])
return (
<LeafletPopup maxHeight={300} minWidth={275} maxWidth={275} autoPanPadding={[20, 5]}
eventHandlers={{
remove: resetPopup
}}
position={props.position}>
<form onSubmit={handleSubmit}>
<div className='flex justify-center'><b className="text-xl font-bold">New {props.layer.name}</b></div>

View File

@ -1,12 +1,15 @@
import { LatLng } from 'leaflet'
import * as React from 'react'
import { Popup as LeafletPopup, useMap } from 'react-leaflet'
import { Item, Tag } from '../../../types'
import { replaceURLs } from '../../../Utils/ReplaceURLs'
import { useRemoveItem } from '../hooks/useItems'
import { NewItemPopupProps } from './NewItemPopup'
export interface UtopiaPopupProps {
item: Item,
tags: Tag[],
setNewItemPopup?: React.Dispatch<React.SetStateAction<NewItemPopupProps | null>>
}
@ -17,11 +20,18 @@ const Popup = (props: UtopiaPopupProps) => {
const map = useMap();
const removeItemFromMap = (event: React.MouseEvent<HTMLElement>) => {
removeItem(item)
event.stopPropagation()
removeItem(item);
event.stopPropagation();
map.closePopup();
}
const openEditPopup = (event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation();
map.closePopup();
if(props.setNewItemPopup)
props.setNewItemPopup({position: new LatLng(item.position.coordinates[1],item.position.coordinates[0]), layer: item.layer, item: item, setNewItemPopup: props.setNewItemPopup})
}
return (
<LeafletPopup maxHeight={300} minWidth={275} maxWidth={275} autoPanPadding={[20, 5]}>
<div className='flex flex-row'>
@ -37,7 +47,7 @@ const Popup = (props: UtopiaPopupProps) => {
</label>
<ul tabIndex={0} className="dropdown-content menu p-2 shadow bg-base-100 rounded-box">
<li>
<a className='bg-white hover:bg-white text-gray-500 hover:text-gray-700'>
<a className='bg-white hover:bg-white text-gray-500 hover:text-gray-700' onClick={openEditPopup}>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
</svg>

View File

@ -12,6 +12,7 @@ import { ItemsProvider } from "./hooks/useItems";
import { TagsProvider } from "./hooks/useTags";
import { LayersProvider } from "./hooks/useLayers";
export interface MapEventListenerProps {
selectMode: Layer | null,
setSelectMode: React.Dispatch<React.SetStateAction<any>>,
@ -44,6 +45,8 @@ function UtopiaMap({
const [selectMode, setSelectMode] = useState<Layer | null>(null);
const [newItemPopup, setNewItemPopup] = useState<NewItemPopupProps | null>(null);
return (
<LayersProvider initialLayers={[]}>
<TagsProvider initialTags={[]}>
@ -54,11 +57,15 @@ function UtopiaMap({
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
<MarkerClusterGroup showCoverageOnHover chunkedLoading maxClusterRadius={50}>
{children}
{
React.Children.toArray(children).map((child) =>
React.isValidElement<{ setNewItemPopup: React.Dispatch<React.SetStateAction<NewItemPopupProps | null>> }>(child) ? React.cloneElement(child, { setNewItemPopup: setNewItemPopup }) : child
)
}
</MarkerClusterGroup>
<MapEventListener setSelectMode={setSelectMode} selectMode={selectMode} setNewItemPopup={setNewItemPopup} />
{newItemPopup &&
<NewItemPopup position={newItemPopup.position} layer={newItemPopup.layer} setNewItemPopup={setNewItemPopup} />
<NewItemPopup position={newItemPopup.position} layer={newItemPopup.layer} setNewItemPopup={setNewItemPopup} item={newItemPopup.item}/>
}
<AddButton setSelectMode={setSelectMode}></AddButton>
</MapContainer>
@ -71,12 +78,10 @@ function UtopiaMap({
</div>
</div>
}
</div>
</ItemsProvider>
</TagsProvider>
</LayersProvider>
);
}

View File

@ -4,6 +4,7 @@ import { Item } from "../../../types";
type ActionType =
| { type: "ADD"; item: Item }
| { type: "UPDATE"; item: Item }
| { type: "REMOVE"; item: Item };
type UseItemManagerResult = ReturnType<typeof useItemsManager>;
@ -11,12 +12,14 @@ type UseItemManagerResult = ReturnType<typeof useItemsManager>;
const ItemContext = createContext<UseItemManagerResult>({
items: [],
addItem: () => {},
updateItem: () => {},
removeItem: () => {}
});
function useItemsManager (initialItems: Item[]): {
items: Item[];
addItem: (item: Item) => void;
updateItem: (item: Item) => void;
removeItem: (item: Item) => void;
} {
const [items, dispatch] = useReducer((state: Item[], action: ActionType) => {
@ -26,6 +29,13 @@ function useItemsManager (initialItems: Item[]): {
...state,
action.item,
];
case "UPDATE":
return state.map((item) => {
if (item.id === action.item.id) {
return action.item
}
return item
});
case "REMOVE":
return state.filter(item => item !== action.item);
default:
@ -40,13 +50,20 @@ function useItemsManager (initialItems: Item[]): {
});
}, []);
const updateItem = useCallback((item: Item) => {
dispatch({
type: "UPDATE",
item,
});
}, []);
const removeItem = useCallback((item: Item) => {
dispatch({
type: "REMOVE",
item,
});
}, []);
return { items, addItem, removeItem };
return { items, updateItem, addItem, removeItem };
}
export const ItemsProvider: React.FunctionComponent<{
@ -67,6 +84,11 @@ export const useAddItem = (): UseItemManagerResult["addItem"] => {
return addItem;
};
export const useUpdateItem = (): UseItemManagerResult["updateItem"] => {
const { updateItem } = useContext(ItemContext);
return updateItem;
};
export const useRemoveItem = (): UseItemManagerResult["removeItem"] => {
const { removeItem } = useContext(ItemContext);
return removeItem;

View File

@ -20,17 +20,10 @@ function useLayerManager(initialLayers: Layer[]): {
const [layers, dispatch] = useReducer((state: Layer[], action: ActionType) => {
switch (action.type) {
case "ADD LAYER":
{
if (!state.includes(action.layer))
state.push(action.layer);
return state;
}
case "ADD 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;
}
return [
...state,
action.layer,
];
default:
throw new Error();
}

View File

@ -1,4 +1,5 @@
import { LatLng } from "leaflet";
import { NewItemPopupProps } from "./Components/Map/Subcomponents/NewItemPopup";
export interface UtopiaMap {
height?: string,
@ -21,20 +22,21 @@ export interface Layer {
markerShape: string,
markerDefaultColor: string,
tags?: Tag[],
setNewItemPopup?: React.Dispatch<React.SetStateAction<NewItemPopupProps | null>>
}
export class Item {
id: number;
id: string | number;
date_created?: string;
date_updated?: string | null;
name: string;
text: string;
position: Geometry;
layer?: Layer;
layer: Layer;
start?: string;
end?: string;
tags?: number[];
constructor(id:number,name:string,text:string,position:Geometry, layer: Layer){
constructor(id:string|number,name:string,text:string,position:Geometry, layer: Layer){
this.id = id;
this.name = name;
this.text = text;
@ -54,7 +56,7 @@ export class Geometry {
export interface Tag {
color: string;
id: number;
id: string | number;
name: string;
}