mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
update Items
This commit is contained in:
parent
3f540ff2d4
commit
de929beb45
@ -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/",
|
||||
|
||||
@ -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>
|
||||
);
|
||||
})
|
||||
|
||||
@ -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" >
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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='© <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>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
10
src/types.ts
10
src/types.ts
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user