update item position

This commit is contained in:
Anton Tranelis 2024-03-24 13:34:38 +01:00
parent 228dc71974
commit 0aa96a45e6
7 changed files with 228 additions and 133 deletions

View File

@ -13,6 +13,7 @@ import { FilterProvider } from '../Map/hooks/useFilter'
import { ItemsProvider } from '../Map/hooks/useItems'
import { LayersProvider } from '../Map/hooks/useLayers'
import { LeafletRefsProvider } from '../Map/hooks/useLeafletRefs'
import { SelectPositionProvider } from '../Map/hooks/useSetItemPosition'
export function AppShell({ appName, nameWidth, children, assetsApi }: { appName: string, nameWidth?: number, children: React.ReactNode, assetsApi: AssetsApi }) {
@ -26,31 +27,33 @@ export function AppShell({ appName, nameWidth, children, assetsApi }: { appName:
<LayersProvider initialLayers={[]}>
<FilterProvider initialTags={[]}>
<ItemsProvider initialItems={[]}>
<LeafletRefsProvider initialLeafletRefs={{}}>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AssetsProvider>
<SetAssetsApi assetsApi={assetsApi}></SetAssetsApi>
<QuestsProvider initialOpen={true}>
<ToastContainer position="top-right"
autoClose={2000}
hideProgressBar
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="light" />
<NavBar appName={appName} nameWidth={nameWidth}></NavBar>
<div id="app-content" className="tw-flex tw-!pl-[77px]">
{children}
</div>
</QuestsProvider>
</AssetsProvider>
</BrowserRouter>
</QueryClientProvider>
</LeafletRefsProvider>
<SelectPositionProvider>
<LeafletRefsProvider initialLeafletRefs={{}}>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AssetsProvider>
<SetAssetsApi assetsApi={assetsApi}></SetAssetsApi>
<QuestsProvider initialOpen={true}>
<ToastContainer position="top-right"
autoClose={2000}
hideProgressBar
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="light" />
<NavBar appName={appName} nameWidth={nameWidth}></NavBar>
<div id="app-content" className="tw-flex tw-!pl-[77px]">
{children}
</div>
</QuestsProvider>
</AssetsProvider>
</BrowserRouter>
</QueryClientProvider>
</LeafletRefsProvider>
</SelectPositionProvider>
</ItemsProvider>
</FilterProvider>
</LayersProvider>

View File

@ -4,7 +4,8 @@ import { useHasUserPermission } from "../../hooks/usePermissions";
import { getValue } from "../../../../Utils/GetValue";
import { useAssetApi } from '../../../AppShell/hooks/useAssets'
import DialogModal from "../../../Templates/DialogModal";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useSetSelectPosition } from "../../hooks/useSetItemPosition";
@ -24,12 +25,10 @@ export function HeaderView({ item, api, editCallback, deleteCallback, itemNameFi
const [modalOpen, setModalOpen] = React.useState<boolean>(false);
const hasUserPermission = useHasUserPermission();
const navigate = useNavigate();
const assetsApi = useAssetApi();
const setSelectPosition = useSetSelectPosition();
const avatar = itemAvatarField && getValue(item, itemAvatarField) ? assetsApi.url + getValue(item, itemAvatarField) + `${big ? "?width=160&heigth=160": "?width=80&heigth=80"}` : item.layer?.itemAvatarField && item && getValue(item, item.layer?.itemAvatarField) && assetsApi.url + getValue(item, item.layer?.itemAvatarField) + `${big ? "?width=160&heigth=160": "?width=80&heigth=80"}`;
const title = itemNameField ? getValue(item, itemNameField) : item.layer?.itemNameField && item && getValue(item, item.layer?.itemNameField);
@ -64,13 +63,19 @@ export function HeaderView({ item, api, editCallback, deleteCallback, itemNameFi
</label>
<ul tabIndex={0} className="tw-dropdown-content tw-menu tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-z-1000">
{((api?.updateItem && hasUserPermission(api.collectionName!, "update", item)) || item.layer?.customEditLink) && <li>
<a className="!tw-text-base-content tw-cursor-pointer" onClick={editCallback}>
<a className="!tw-text-base-content tw-cursor-pointer" onClick={() => item.layer?.customEditLink? navigate(item.layer.customEditLink) : editCallback}>
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-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>
</a>
</li>}
{((api?.updateItem && hasUserPermission(api.collectionName!, "update", item))) && <li>
<a className="!tw-text-base-content tw-cursor-pointer" onClick={() => setSelectPosition(item)}>
<svg stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 512 512" className="tw-w-5 tw-h-5" xmlns="http://www.w3.org/2000/svg">
<path d="M256 0c17.7 0 32 14.3 32 32V42.4c93.7 13.9 167.7 88 181.6 181.6H480c17.7 0 32 14.3 32 32s-14.3 32-32 32H469.6c-13.9 93.7-88 167.7-181.6 181.6V480c0 17.7-14.3 32-32 32s-32-14.3-32-32V469.6C130.3 455.7 56.3 381.7 42.4 288H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H42.4C56.3 130.3 130.3 56.3 224 42.4V32c0-17.7 14.3-32 32-32zM107.4 288c12.5 58.3 58.4 104.1 116.6 116.6V384c0-17.7 14.3-32 32-32s32 14.3 32 32v20.6c58.3-12.5 104.1-58.4 116.6-116.6H384c-17.7 0-32-14.3-32-32s14.3-32 32-32h20.6C392.1 165.7 346.3 119.9 288 107.4V128c0 17.7-14.3 32-32 32s-32-14.3-32-32V107.4C165.7 119.9 119.9 165.7 107.4 224H128c17.7 0 32 14.3 32 32s-14.3 32-32 32H107.4zM256 224a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"></path>
</svg>
</a>
</li>}
{api?.deleteItem && hasUserPermission(api.collectionName!, "delete", item) && <li>
<a className='tw-cursor-pointer !tw-text-error' onClick={openDeleteModal}>
{loading ? <span className="tw-loading tw-loading-spinner tw-loading-sm"></span>

View File

@ -1,7 +1,7 @@
import { TileLayer, MapContainer, useMapEvents } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import * as React from "react";
import { LayerProps, UtopiaMapProps } from "../../types"
import { Geometry, Item, LayerProps, UtopiaMapProps } from "../../types"
import "./UtopiaMap.css"
import { LatLng } from "leaflet";
import MarkerClusterGroup from 'react-leaflet-cluster'
@ -12,12 +12,15 @@ import { SearchControl } from "./Subcomponents/Controls/SearchControl";
import { LayerControl } from "./Subcomponents/Controls/LayerControl";
import { QuestControl } from "./Subcomponents/Controls/QuestControl";
import { Control } from "./Subcomponents/Controls/Control";
import { Outlet, useLocation } from "react-router-dom";
import { Outlet, useLocation, useNavigate } from "react-router-dom";
import { TagsControl } from "./Subcomponents/Controls/TagsControl";
import { useSelectPosition, useSetSelectPosition } from "./hooks/useSetItemPosition";
import { useUpdateItem } from "./hooks/useItems";
import { toast } from "react-toastify";
export interface MapEventListenerProps {
selectNewItemPosition: LayerProps | null,
selectNewItemPosition: LayerProps | Item | null,
setSelectNewItemPosition: React.Dispatch<any>,
setItemFormPopup: React.Dispatch<React.SetStateAction<any>>
}
@ -45,31 +48,53 @@ function UtopiaMap({
console.log(e.latlng.lat + ',' + e.latlng.lng);
if (props.selectNewItemPosition != null) {
props.setItemFormPopup({ layer: props.selectNewItemPosition, position: e.latlng })
props.setSelectNewItemPosition(null)
if ('menuIcon' in props.selectNewItemPosition) {
props.setItemFormPopup({ layer: props.selectNewItemPosition, position: e.latlng })
props.setSelectNewItemPosition(null)
}
if ('position' in props.selectNewItemPosition) {
const position = new Geometry(e.latlng.lng,e.latlng.lat);
itemUpdate({...selectNewItemPosition as Item, position: position })
setSelectNewItemPosition(null);
}
}
},
moveend: (e) => {
console.log(e);
}
})
return null
}
const [selectNewItemPosition, setSelectNewItemPosition] = useState<LayerProps | null>(null);
const [itemFormPopup, setItemFormPopup] = useState<ItemFormPopupProps | null>(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 })
success = true;
} catch (error) {
toast.error(error.toString());
}
if (success) {
updateItem(updatedItem)
toast.success("Item position updated");
navigate("/" + updatedItem.layer?.name + "/" + updatedItem.id)
}
}
const selectNewItemPosition = useSelectPosition();
const setSelectNewItemPosition = useSetSelectPosition();
const clusterRef = React.useRef();
const location = useLocation();
const updateItem = useUpdateItem();
const navigate = useNavigate();
const [itemFormPopup, setItemFormPopup] = useState<ItemFormPopupProps | null>(null);
useEffect(() => {
let params = new URLSearchParams(location.search);
let urlPosition = params.get("position");
}, [location]);
@ -105,6 +130,10 @@ function UtopiaMap({
<AddButton triggerAction={setSelectNewItemPosition}></AddButton>
{selectNewItemPosition != null &&
<div className="tw-button tw-z-1000 tw-absolute tw-right-5 tw-top-4 tw-drop-shadow-md">
<label className="tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600" onClick={() => {
setSelectNewItemPosition(null)
}}>
<p className='tw-text-center '></p></label>
<div className="tw-alert tw-bg-base-100 tw-text-base-content">
<div>
<span>Select {selectNewItemPosition.name} position!</span>

View File

@ -0,0 +1,35 @@
import { createContext, useContext, useState } from "react";
import { Item, LayerProps } from '../../../types';
type UseSelectPositionManagerResult = ReturnType<typeof useSelectPositionManager>;
const SelectPositionContext = createContext<UseSelectPositionManagerResult>({
selectPosition: null,
setSelectPosition: () => { },
});
function useSelectPositionManager(): {
selectPosition: Item | LayerProps | null;
setSelectPosition: React.Dispatch<React.SetStateAction< Item | LayerProps | null>>;
} {
const [selectPosition, setSelectPosition] = useState<LayerProps | null | Item>(null);
return { selectPosition, setSelectPosition };
}
export const SelectPositionProvider: React.FunctionComponent<{
children?: React.ReactNode
}> = ({ children }) => (
<SelectPositionContext.Provider value={useSelectPositionManager()}>
{children}
</SelectPositionContext.Provider>
);
export const useSelectPosition = (): Item | LayerProps | null => {
const { selectPosition } = useContext(SelectPositionContext);
return selectPosition;
};
export const useSetSelectPosition = (): UseSelectPositionManagerResult["setSelectPosition"] => {
const { setSelectPosition } = useContext(SelectPositionContext);
return setSelectPosition;
}

View File

@ -0,0 +1,10 @@
import { useMap } from "react-leaflet"
export const setItemLocation = () => {
const map = useMap();
return (
<div></div>
)
}

View File

@ -3,7 +3,6 @@ import { useAddItem, useItems, useRemoveItem, useUpdateItem } from '../Map/hooks
import { useLocation, useNavigate } from 'react-router-dom'
import { useEffect, useRef, useState } from 'react';
import { Item } from '../../types';
import { getValue } from '../../Utils/GetValue';
import { useMap } from 'react-leaflet';
import { LatLng } from 'leaflet';
import { PopupStartEndInput, StartEndView, TextView } from '../Map';
@ -20,6 +19,8 @@ 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 { useLeafletRefs } from '../Map/hooks/useLeafletRefs';
export function OverlayItemProfile() {
@ -33,6 +34,7 @@ export function OverlayItemProfile() {
const [updatePermission, setUpdatePermission] = useState<boolean>(false);
const layers = useLayers();
const selectPosition = useSelectPosition();
const removeItem = useRemoveItem();
@ -97,9 +99,9 @@ export function OverlayItemProfile() {
}, [location, items, activeTab])
useEffect(() => {
useEffect(() => {
let params = new URLSearchParams(location.search);
let urlTab = params.get("tab");
let urlTab = params.get("tab");
urlTab ? setActiveTab(Number(urlTab)) : setActiveTab(1);
}, [location])
@ -119,6 +121,14 @@ export function OverlayItemProfile() {
}, [item])
const [selecting, setSelecting] = useState<boolean>(false);
useEffect(() => {
selectPosition && map.closePopup();
}, [selectPosition])
const submitNewItem = async (evt: any, type: string) => {
evt.preventDefault();
const formItem: Item = {} as Item;
@ -203,129 +213,133 @@ export function OverlayItemProfile() {
setLoading(true);
let success = false;
try {
await item.layer?.api?.deleteItem!(item.id)
success = true;
await item.layer?.api?.deleteItem!(item.id)
success = true;
} catch (error) {
toast.error(error.toString());
toast.error(error.toString());
}
if (success) {
removeItem(item);
toast.success("Item deleted");
removeItem(item);
toast.success("Item deleted");
}
setLoading(false);
map.closePopup();
let params = new URLSearchParams(window.location.search);
window.history.pushState({}, "", "/" + `${params ? `?${params}` : ""}`);
navigate("/");
}
}
return (
<MapOverlayPage className='tw-mx-4 tw-mt-4 tw-max-h-[calc(100dvh-96px)] tw-h-[calc(100dvh-96px)] md:tw-w-[calc(50%-32px)] tw-w-[calc(100%-32px)] tw-min-w-80 tw-max-w-3xl !tw-left-auto tw-top-0 tw-bottom-0'>
{item &&
<>
<HeaderView api={item.layer?.api} item={item} deleteCallback={handleDelete} editCallback={ () => navigate("/edit-item/"+item.id)} big/>
<>
{item &&
<MapOverlayPage className={`tw-mx-4 tw-mt-4 tw-max-h-[calc(100dvh-96px)] tw-h-[calc(100dvh-96px)] md:tw-w-[calc(50%-32px)] tw-w-[calc(100%-32px)] tw-min-w-80 tw-max-w-3xl !tw-left-auto tw-top-0 tw-bottom-0 tw-transition-opacity tw-duration-500 ${!selectPosition ? 'tw-opacity-100 tw-pointer-events-auto' : 'tw-opacity-0 tw-pointer-events-none'}`}>
<>
<HeaderView api={item.layer?.api} item={item} deleteCallback={handleDelete} editCallback={() => navigate("/edit-item/" + item.id)} big />
<div className='tw-h-full'>
<div className='tw-h-full'>
<div role="tablist" className="tw-tabs tw-tabs-lifted tw-mt-2 tw-mb-2">
<input type="radio" name="my_tabs_2" role="tab" className={`tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]`} aria-label="Info" checked={activeTab == 1 && true} onChange={() => updateActiveTab(1)} />
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto fade tw-pt-2 tw-pb-4 tw-mb-4 tw-overflow-x-hidden">
<TextView item={item} />
</div>
<div role="tablist" className="tw-tabs tw-tabs-lifted tw-mt-2 tw-mb-2">
<input type="radio" name="my_tabs_2" role="tab" className={`tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]`} aria-label="Info" checked={activeTab == 1 && true} onChange={() => updateActiveTab(1)} />
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto fade tw-pt-2 tw-pb-4 tw-mb-4 tw-overflow-x-hidden">
<TextView item={item} />
</div>
<input type="radio" name="my_tabs_2" role="tab" className="tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]" aria-label="Projects" checked={activeTab == 2 && true} onChange={() => updateActiveTab(2)} />
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto tw-pt-4 tw-pb-1 -tw-mx-4 tw-overflow-x-hidden" >
<div className='tw-h-full'>
<div className='tw-grid tw-grid-cols-1 sm:tw-grid-cols-2 md:tw-grid-cols-1 lg:tw-grid-cols-1 xl:tw-grid-cols-2 tw-pb-5'>
{relations && relations.map(i => {
if (i.type == 'project') return (
<input type="radio" name="my_tabs_2" role="tab" className="tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]" aria-label="Projects" checked={activeTab == 2 && true} onChange={() => updateActiveTab(2)} />
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto tw-pt-4 tw-pb-1 -tw-mx-4 tw-overflow-x-hidden" >
<div className='tw-h-full'>
<div className='tw-grid tw-grid-cols-1 sm:tw-grid-cols-2 md:tw-grid-cols-1 lg:tw-grid-cols-1 xl:tw-grid-cols-1 2xl:tw-grid-cols-2 tw-pb-5'>
{relations && relations.map(i => {
if (i.type == 'project') return (
<div key={i.id} className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-mx-4 tw-p-4 tw-mb-4 tw-h-fit' onClick={() => navigate('/item/' + i.id)}>
<LinkedItemsHeaderView unlinkPermission={updatePermission} loading={loading} item={i} unlinkCallback={unlinkItem} />
<div key={i.id} className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-mx-4 tw-p-4 tw-mb-4 tw-h-fit' onClick={() => navigate('/item/' + i.id)}>
<LinkedItemsHeaderView unlinkPermission={updatePermission} loading={loading} item={i} unlinkCallback={unlinkItem} />
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
<TextView truncate item={i} />
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
<TextView truncate item={i} />
</div>
</div>
</div>
)
else return null
})}
{addItemPopupType == "project" ?
<form ref={tabRef} autoComplete='off' onSubmit={e => submitNewItem(e, addItemPopupType)} >
)
else return null
})}
{addItemPopupType == "project" ?
<form ref={tabRef} autoComplete='off' onSubmit={e => submitNewItem(e, addItemPopupType)} >
<div className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-mx-4 tw-p-6 tw-mb-4'>
<label className="tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600" onClick={() => {
setAddItemPopupType("")
}}>
<p className='tw-text-center '></p></label>
<TextInput type="text" placeholder="Name" dataField="name" defaultValue={""} inputStyle='' />
<TextAreaInput placeholder="Text" dataField="text" defaultValue={""} inputStyle='tw-h-40 tw-mt-5' />
<div className='tw-flex tw-justify-center'>
<button className={loading ? 'tw-btn tw-btn-disabled tw-mt-5 tw-place-self-center' : 'tw-btn tw-mt-5 tw-place-self-center'} type='submit'>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Save'}</button>
<div className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-mx-4 tw-p-6 tw-mb-4'>
<label className="tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600" onClick={() => {
setAddItemPopupType("")
}}>
<p className='tw-text-center '></p></label>
<TextInput type="text" placeholder="Name" dataField="name" defaultValue={""} inputStyle='' />
<TextAreaInput placeholder="Text" dataField="text" defaultValue={""} inputStyle='tw-h-40 tw-mt-5' />
<div className='tw-flex tw-justify-center'>
<button className={loading ? 'tw-btn tw-btn-disabled tw-mt-5 tw-place-self-center' : 'tw-btn tw-mt-5 tw-place-self-center'} type='submit'>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Save'}</button>
</div>
</div>
</div>
</form> : <></>
}
{updatePermission && <ActionButton collection="items" item={item} existingRelations={relations} itemType={"project"} triggerItemSelected={linkItem} triggerAddButton={() => { setAddItemPopupType("project"); scroll() }} color={item.color}></ActionButton>}
</form> : <></>
}
{updatePermission && <ActionButton collection="items" item={item} existingRelations={relations} itemType={"project"} triggerItemSelected={linkItem} triggerAddButton={() => { setAddItemPopupType("project"); scroll() }} color={item.color}></ActionButton>}
</div>
</div>
</div>
</div>
<input type="radio" name="my_tabs_2" role="tab" className="tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]" aria-label="Events" checked={activeTab == 3 && true} onChange={() => updateActiveTab(3)} />
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto tw-pt-4 tw-pb-1 -tw-mx-4 tw-overflow-x-hidden">
<div className='tw-h-full'>
<div className='tw-grid tw-grid-cols-1 sm:tw-grid-cols-2 md:tw-grid-cols-1 lg:tw-grid-cols-1 xl:tw-grid-cols-2'>
{relations && relations.map(i => {
if (i.type == 'event') return (
<input type="radio" name="my_tabs_2" role="tab" className="tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]" aria-label="Events" checked={activeTab == 3 && true} onChange={() => updateActiveTab(3)} />
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto tw-pt-4 tw-pb-1 -tw-mx-4 tw-overflow-x-hidden">
<div className='tw-h-full'>
<div className='tw-grid tw-grid-cols-1 sm:tw-grid-cols-2 md:tw-grid-cols-1 lg:tw-grid-cols-1 xl:tw-grid-cols-1 2xl:tw-grid-cols-2'>
{relations && relations.map(i => {
if (i.type == 'event') return (
<div key={i.id} className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-mx-4 tw-p-6 tw-mb-4' onClick={() => navigate('/item/' + i.id)}>
<LinkedItemsHeaderView unlinkPermission={updatePermission} item={i} unlinkCallback={unlinkItem} loading={loading} />
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
<StartEndView item={i}></StartEndView>
<TextView truncate item={i} />
<div key={i.id} className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-mx-4 tw-p-6 tw-mb-4' onClick={() => navigate('/item/' + i.id)}>
<LinkedItemsHeaderView unlinkPermission={updatePermission} item={i} unlinkCallback={unlinkItem} loading={loading} />
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
<StartEndView item={i}></StartEndView>
<TextView truncate item={i} />
</div>
</div>
</div>
)
else return null
})}
{addItemPopupType == "event" ?
<form autoComplete='off' onSubmit={e => submitNewItem(e, addItemPopupType)} >
)
else return null
})}
{addItemPopupType == "event" ?
<form autoComplete='off' onSubmit={e => submitNewItem(e, addItemPopupType)} >
<div className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-mx-4 tw-p-4 tw-mb-4'>
<label className="tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600" onClick={() => {
setAddItemPopupType("")
}}>
<p className='tw-text-center '></p></label>
<TextInput type="text" placeholder="Name" dataField="name" defaultValue={""} inputStyle='' />
<PopupStartEndInput></PopupStartEndInput>
<TextAreaInput placeholder="Text" dataField="text" defaultValue={""} inputStyle='tw-h-40 tw-mt-5' />
<div className='tw-flex tw-justify-center'>
<button className={loading ? 'tw-btn tw-btn-disabled tw-mt-5 tw-place-self-center' : 'tw-btn tw-mt-5 tw-place-self-center'} type='submit'>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Save'}</button>
<div className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-mx-4 tw-p-4 tw-mb-4'>
<label className="tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600" onClick={() => {
setAddItemPopupType("")
}}>
<p className='tw-text-center '></p></label>
<TextInput type="text" placeholder="Name" dataField="name" defaultValue={""} inputStyle='' />
<PopupStartEndInput></PopupStartEndInput>
<TextAreaInput placeholder="Text" dataField="text" defaultValue={""} inputStyle='tw-h-40 tw-mt-5' />
<div className='tw-flex tw-justify-center'>
<button className={loading ? 'tw-btn tw-btn-disabled tw-mt-5 tw-place-self-center' : 'tw-btn tw-mt-5 tw-place-self-center'} type='submit'>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Save'}</button>
</div>
</div>
</div>
</form> : <></>
}
{updatePermission && <ActionButton collection="items" item={item} existingRelations={relations} itemType={"event"} triggerItemSelected={linkItem} triggerAddButton={() => { setAddItemPopupType("event"); scroll() }} color={item.color}></ActionButton>}
</form> : <></>
}
{updatePermission && <ActionButton collection="items" item={item} existingRelations={relations} itemType={"event"} triggerItemSelected={linkItem} triggerAddButton={() => { setAddItemPopupType("event"); scroll() }} color={item.color}></ActionButton>}
</div>
</div>
</div>
</div>
<input type="radio" name="my_tabs_2" role="tab" className="tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]" aria-label="Friends" checked={activeTab == 4 && true} onChange={() => updateActiveTab(4)} />
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto fade tw-pt-2 tw-pb-1 tw-overflow-x-hidden">
<input type="radio" name="my_tabs_2" role="tab" className="tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]" aria-label="Friends" checked={activeTab == 4 && true} onChange={() => updateActiveTab(4)} />
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto fade tw-pt-2 tw-pb-1 tw-overflow-x-hidden">
</div>
</div>
</div>
</div>
</>
</>
</MapOverlayPage >
}
</MapOverlayPage >
</>
)
}

View File

@ -14,7 +14,6 @@ import { hashTagRegex } from '../../Utils/HashTagRegex';
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';