From 93cbcf7f156c071b39a9af0a40e86442946c0a9c Mon Sep 17 00:00:00 2001 From: Anton Tranelis Date: Fri, 22 Mar 2024 11:58:27 +0100 Subject: [PATCH] HeaderView and bugfixing --- .../Subcomponents/Controls/SearchControl.tsx | 26 ++- .../ItemPopupComponents/HeaderView.tsx | 160 +++++++----------- .../Map/Subcomponents/ItemViewPopup.tsx | 46 ++++- src/Components/Profile/OverlayItemProfile.tsx | 18 +- src/Components/Templates/ItemsIndexPage.tsx | 83 +++++---- 5 files changed, 176 insertions(+), 157 deletions(-) diff --git a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx index e0a27c7a..919414cd 100644 --- a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx +++ b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx @@ -14,6 +14,7 @@ import { LocateControl } from './LocateControl'; import * as L from 'leaflet'; import MarkerIconFactory from '../../../../Utils/MarkerIconFactory'; import { decodeTag } from '../../../../Utils/FormatTags'; +import { useNavigate } from 'react-router-dom'; @@ -45,6 +46,8 @@ export const SearchControl = ({ clusterRef }) => { } }) + const navigate = useNavigate(); + useDebounce(() => { const searchGeo = async () => { try { @@ -111,18 +114,23 @@ export const SearchControl = ({ clusterRef }) => { {itemsResults.slice(0, 5).map(item => (
{ const marker = Object.entries(leafletRefs).find(r => r[1].item == item)?.[1].marker; - - if (filterTags.length > 0) { - marker !== null && window.history.pushState({}, "", `/${item.layer.name}/${item.id}`) - resetFilterTags(); - hide(); + if(marker){ + if (filterTags.length > 0) { + marker !== null && window.history.pushState({}, "", `/${item.layer.name}/${item.id}`) + resetFilterTags(); + hide(); + } + else { + marker !== null && clusterRef?.current?.zoomToShowLayer(marker, () => { + marker?.openPopup(); + hide(); + }); + } } else { - marker !== null && clusterRef?.current?.zoomToShowLayer(marker, () => { - marker?.openPopup(); - hide(); - }); + navigate("item/"+item.id) } + } }>
diff --git a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx index ea9d3f78..7d7f2692 100644 --- a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx +++ b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx @@ -1,12 +1,8 @@ import * as React from "react" import { useRemoveItem } from "../../hooks/useItems"; -import { useMap } from "react-leaflet"; -import { ItemFormPopupProps } from "../ItemFormPopup"; -import { LatLng } from "leaflet"; -import { Item } from "../../../../types"; +import { Item, ItemsApi } 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' import DialogModal from "../../../Templates/DialogModal"; @@ -15,129 +11,97 @@ import { useNavigate } from "react-router-dom"; -export function HeaderView({ item, setItemFormPopup, hideMenu=false }: { +export function HeaderView({ item, api, editCallback, deleteCallback, itemNameField, itemAvatarField, loading, hideMenu = false }: { item: Item, - setItemFormPopup?: React.Dispatch>, + api?: ItemsApi, + editCallback?: any, + deleteCallback?: any, + itemNameField?: string, + itemAvatarField?: string, + loading?: boolean, hideMenu?: boolean }) { const [modalOpen, setModalOpen] = React.useState(false); - const [loading, setLoading] = React.useState(false); - const removeItem = useRemoveItem(); - const map = useMap(); const hasUserPermission = useHasUserPermission(); - const { user } = useAuth(); const assetsApi = useAssetApi(); - const navigate = useNavigate(); - - 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 avatar = itemAvatarField && getValue(item, itemAvatarField) ? assetsApi.url + getValue(item, itemAvatarField) : item.layer?.itemAvatarField && item && getValue(item, item.layer?.itemAvatarField) && assetsApi.url + getValue(item, item.layer?.itemAvatarField); + const title = itemNameField ? getValue(item, itemNameField) : item.layer?.itemNameField && item && getValue(item, item.layer?.itemNameField); - const removeItemFromMap = async (event: React.MouseEvent) => { - event.stopPropagation(); - setLoading(true); - let success = false; - try { - await item.layer?.api?.deleteItem!(item.id) - success = true; - } catch (error) { - toast.error(error.toString()); - } - if (success) { - removeItem(item); - toast.success("Item deleted"); - } - setLoading(false); - map.closePopup(); - let params = new URLSearchParams(window.location.search); - window.history.pushState({}, "", "/" + `${params? `?${params}` : ""}`); - setModalOpen(false); - navigate("/"); - - - } const openDeleteModal = async (event: React.MouseEvent) => { setModalOpen(true); event.stopPropagation(); } - const openEditPopup = (event: React.MouseEvent) => { - event.stopPropagation(); - map.closePopup(); - if (setItemFormPopup && item.position) - setItemFormPopup({ position: new LatLng(item.position.coordinates[1], item.position.coordinates[0]), layer: item.layer!, item: item, setItemFormPopup: setItemFormPopup }) - } return ( <> -
-
-
{ - avatar ? -
- -
- : - "" - } +
+
+
{ + avatar ? +
+ +
+ : + "" + } {title ? title : item.name} +
+
+
e.stopPropagation()}> + {(api?.deleteItem || item.layer?.api?.updateItem) + && (hasUserPermission(api?.collectionName!, "delete", item) || hasUserPermission(api?.collectionName!, "update", item)) + && !hideMenu && +
+ +
    + {((api?.updateItem && hasUserPermission(api.collectionName!, "update", item)) || item.layer?.customEditLink) &&
  • + + + + + +
  • } + + {api?.deleteItem && hasUserPermission(api.collectionName!, "delete", item) &&
  • + + {loading ? + : + + + } + +
  • } +
+
}
-
e.stopPropagation()}> - {(item.layer?.api?.deleteItem || item.layer?.api?.updateItem) - && (hasUserPermission(item.layer.api?.collectionName!, "delete", item) || hasUserPermission(item.layer.api?.collectionName!, "update", item)) - && !hideMenu && -
- - -
} -
-
- (setModalOpen(false)) }> - Do you want to delete {item.name}? -
-
- - -
+ (setModalOpen(false))} > +
e.stopPropagation()} > + Do you want to delete {item.name}? +
+
+ +
- +
+
+
) } diff --git a/src/Components/Map/Subcomponents/ItemViewPopup.tsx b/src/Components/Map/Subcomponents/ItemViewPopup.tsx index 078888c8..4b1ba13b 100644 --- a/src/Components/Map/Subcomponents/ItemViewPopup.tsx +++ b/src/Components/Map/Subcomponents/ItemViewPopup.tsx @@ -1,11 +1,15 @@ import * as React from 'react' -import { Popup as LeafletPopup } from 'react-leaflet' +import { Popup as LeafletPopup, useMap } from 'react-leaflet' import { Item } from '../../../types' import { ItemFormPopupProps } from './ItemFormPopup' import { HeaderView } from './ItemPopupComponents/HeaderView' import { TextView } from './ItemPopupComponents/TextView' import { timeAgo } from '../../../Utils/TimeAgo' import { useState } from 'react' +import { LatLng } from 'leaflet' +import { useNavigate } from 'react-router-dom' +import { useRemoveItem } from '../hooks/useItems' +import { toast } from 'react-toastify' export interface ItemViewPopupProps { @@ -17,12 +21,46 @@ export interface ItemViewPopupProps { export const ItemViewPopup = React.forwardRef((props: ItemViewPopupProps, ref: any) => { + const map = useMap(); + const [loading, setLoading] = React.useState(false); + const removeItem = useRemoveItem(); + const navigate = useNavigate(); + + const [infoExpanded, setInfoExpanded] = useState(false); + const handleEdit = (event: React.MouseEvent) => { + event.stopPropagation(); + map.closePopup(); + props.setItemFormPopup && props.setItemFormPopup({ position: new LatLng(props.item.position?.coordinates[1]!, props.item.position?.coordinates[0]!), layer: props.item.layer!, item: props.item, setItemFormPopup: props.setItemFormPopup }) + } + + const handleDelete = async (event: React.MouseEvent) => { + event.stopPropagation(); + setLoading(true); + let success = false; + try { + await props.item.layer?.api?.deleteItem!(props.item.id) + success = true; + } catch (error) { + toast.error(error.toString()); + } + if (success) { + removeItem(props.item); + toast.success("Item deleted"); + } + setLoading(false); + map.closePopup(); + let params = new URLSearchParams(window.location.search); + window.history.pushState({}, "", "/" + `${params ? `?${params}` : ""}`); + navigate("/"); + } + + return (
- +
{props.children ? @@ -48,8 +86,8 @@ export const ItemViewPopup = React.forwardRef((props: ItemViewPopupProps, ref: a

setInfoExpanded(true)}>ⓘ

}
-{ //** */ - } + { //** */ + }
diff --git a/src/Components/Profile/OverlayItemProfile.tsx b/src/Components/Profile/OverlayItemProfile.tsx index 1034d86b..e6f1375c 100644 --- a/src/Components/Profile/OverlayItemProfile.tsx +++ b/src/Components/Profile/OverlayItemProfile.tsx @@ -65,6 +65,11 @@ export function OverlayItemProfile() { scroll(); }, [addItemPopupType]) + useEffect(() => { + console.log(addItemPopupType); + + }, [addItemPopupType]) + useEffect(() => { @@ -108,8 +113,12 @@ export function OverlayItemProfile() { } }); const uuid = crypto.randomUUID(); - const layer = layers.find(l => l.name = addItemPopupType) + console.log(layers); + + const layer = layers.find(l => l.name.toLocaleLowerCase().replace("s","") == addItemPopupType.toLocaleLowerCase()) + console.log(layer); + let success = false; try { await layer?.api?.createItem!({ ...formItem, id: uuid, type: type }); @@ -169,12 +178,13 @@ export function OverlayItemProfile() { setActiveTab(2)} />
-
+
{relations && relations.map(i => { if (i.type == 'project') return (
navigate('/item/' + i.id)}> - + navigate("/edit-item/"+i.id)}> +
@@ -206,7 +216,7 @@ export function OverlayItemProfile() {
setActiveTab(3)} /> -
+
{relations && relations.map(i => { diff --git a/src/Components/Templates/ItemsIndexPage.tsx b/src/Components/Templates/ItemsIndexPage.tsx index cd532954..749ddcfa 100644 --- a/src/Components/Templates/ItemsIndexPage.tsx +++ b/src/Components/Templates/ItemsIndexPage.tsx @@ -15,6 +15,7 @@ import { randomColor } from '../../Utils/RandomColor'; import { useAuth } from '../Auth'; import { useLayers } from '../Map/hooks/useLayers'; import { PermissionsProvider } from '../Map/hooks/usePermissions'; +import { HeaderView } from '../Map/Subcomponents/ItemPopupComponents/HeaderView'; type breadcrumb = { @@ -33,7 +34,7 @@ export const ItemsIndexPage = ({ api, url, parameterField, breadcrumbs, itemName const tabRef = useRef(null); function scroll() { - tabRef.current?.scrollIntoView(); + tabRef.current?.scrollIntoView(); } useEffect(() => { @@ -67,33 +68,51 @@ export const ItemsIndexPage = ({ api, url, parameterField, breadcrumbs, itemName evt.preventDefault(); const formItem: Item = {} as Item; Array.from(evt.target).forEach((input: HTMLInputElement) => { - if (input.name) { - formItem[input.name] = input.value; - } + if (input.name) { + formItem[input.name] = input.value; + } }); setLoading(true); formItem.text && formItem.text.toLocaleLowerCase().match(hashTagRegex)?.map(tag => { - if (!tags.find((t) => t.name.toLocaleLowerCase() === tag.slice(1).toLocaleLowerCase())) { - addTag({ id: crypto.randomUUID(), name: tag.slice(1), color: randomColor() }) - } + if (!tags.find((t) => t.name.toLocaleLowerCase() === tag.slice(1).toLocaleLowerCase())) { + addTag({ id: crypto.randomUUID(), name: tag.slice(1), color: randomColor() }) + } }); const uuid = crypto.randomUUID(); let success = false; try { - await api?.createItem!({ ...formItem, id: uuid, type: type }); - success = true; + await api?.createItem!({ ...formItem, id: uuid, type: type }); + success = true; } catch (error) { - toast.error(error.toString()); + toast.error(error.toString()); } if (success) { - addItem({ ...formItem, id: uuid, type: type, layer: layers.find(l => l.name == addItemPopupType), user_created: user }); - toast.success("New item created"); - resetFilterTags(); + addItem({ ...formItem, id: uuid, type: type, layer: layers.find(l => l.name == addItemPopupType), user_created: user }); + toast.success("New item created"); + resetFilterTags(); } setLoading(false); setAddItemPopupType(""); - setItems(current => [...current,{ ...formItem, id: uuid, type: type, layer: layers.find(l => l.name == addItemPopupType), user_created: user } ]) -} + setItems(current => [...current, { ...formItem, id: uuid, type: type, layer: layers.find(l => l.name == addItemPopupType), user_created: user }]) + } + + const deleteItem = async (item) => { + setLoading(true); + let success = false; + try { + await api?.deleteItem!(item.id) + success = true; + } catch (error) { + toast.error(error.toString()); + } + if (success) { + toast.success("Item deleted"); + } + setLoading(false); + setItems(items.filter(i=>i.id !=item.id)) + console.log("chaka"); + + } return ( @@ -121,32 +140,12 @@ export const ItemsIndexPage = ({ api, url, parameterField, breadcrumbs, itemName { items?.map((i, k) => { return ( - - -
navigate(url + getValue(i,parameterField))}> - -
-
-
{ - getValue(i, itemImageField) ? -
- -
- : - "" - } - {getValue(i, itemNameField)} - -
-
-
- -
-
-
- -
+
navigate(url + getValue(i, parameterField))}> + navigate("/edit-item/"+i.id)} deleteCallback={()=>deleteItem(i)}> +
+
+
) @@ -154,7 +153,7 @@ export const ItemsIndexPage = ({ api, url, parameterField, breadcrumbs, itemName } {addItemPopupType == "project" ? -
submitNewItem(e, addItemPopupType)} > + submitNewItem(e, addItemPopupType)} >
- {setAddItemPopupType("project"); scroll();}} color={'#777'} collection='items'/> + { setAddItemPopupType("project"); scroll(); }} color={'#777'} collection='items' /> {children}