mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
HeaderView and bugfixing
This commit is contained in:
parent
0b717f35fe
commit
93cbcf7f15
@ -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 => (
|
||||
<div key={item.id} className='tw-cursor-pointer hover:tw-font-bold' onClick={() => {
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
}><div className='tw-flex tw-flex-row'>
|
||||
<item.layer.menuIcon className="tw-text-current tw-w-5 tw-mr-2 tw-mt-0" />
|
||||
|
||||
@ -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<React.SetStateAction<ItemFormPopupProps | null>>,
|
||||
api?: ItemsApi<any>,
|
||||
editCallback?: any,
|
||||
deleteCallback?: any,
|
||||
itemNameField?: string,
|
||||
itemAvatarField?: string,
|
||||
loading?: boolean,
|
||||
hideMenu?: boolean
|
||||
}) {
|
||||
|
||||
|
||||
const [modalOpen, setModalOpen] = React.useState<boolean>(false);
|
||||
|
||||
const [loading, setLoading] = React.useState<boolean>(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<HTMLElement>) => {
|
||||
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<HTMLElement>) => {
|
||||
setModalOpen(true);
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
const openEditPopup = (event: React.MouseEvent<HTMLElement>) => {
|
||||
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 (
|
||||
<>
|
||||
<div className='tw-grid tw-grid-cols-6 tw-pb-2'>
|
||||
<div className='tw-col-span-5'>
|
||||
<div className="tw-flex tw-flex-row">{
|
||||
avatar ?
|
||||
<div className="tw-w-10 tw-min-w-[2.5em] tw-rounded-full">
|
||||
<img className="tw-rounded-full" src={`${avatar}?width=80&height=80`} />
|
||||
</div>
|
||||
:
|
||||
""
|
||||
}
|
||||
<div className='tw-grid tw-grid-cols-6 tw-pb-2'>
|
||||
<div className='tw-col-span-5'>
|
||||
<div className="tw-flex tw-flex-row">{
|
||||
avatar ?
|
||||
<div className="tw-w-10 tw-min-w-[2.5em] tw-rounded-full">
|
||||
<img className="tw-rounded-full" src={`${avatar}?width=80&height=80`} />
|
||||
</div>
|
||||
:
|
||||
""
|
||||
}
|
||||
<b className={`tw-text-xl tw-font-bold ${avatar ? "tw-ml-2 tw-mt-1" : ""}`}>{title ? title : item.name}</b>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className='tw-col-span-1' onClick={(e) => e.stopPropagation()}>
|
||||
{(api?.deleteItem || item.layer?.api?.updateItem)
|
||||
&& (hasUserPermission(api?.collectionName!, "delete", item) || hasUserPermission(api?.collectionName!, "update", item))
|
||||
&& !hideMenu &&
|
||||
<div className="tw-dropdown tw-dropdown-bottom">
|
||||
<label tabIndex={0} className="tw-bg-base-100 tw-btn tw-m-1 tw-leading-3 tw-border-none tw-min-h-0 tw-h-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
|
||||
</svg>
|
||||
</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}>
|
||||
<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?.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>
|
||||
:
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fillRule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clipRule="evenodd" />
|
||||
</svg>}
|
||||
</a>
|
||||
</li>}
|
||||
</ul>
|
||||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
<div className='tw-col-span-1' onClick={(e)=>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 &&
|
||||
<div className="tw-dropdown tw-dropdown-bottom">
|
||||
<label tabIndex={0} className="tw-bg-base-100 tw-btn tw-m-1 tw-leading-3 tw-border-none tw-min-h-0 tw-h-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
|
||||
</svg>
|
||||
</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">
|
||||
{((item.layer.api.updateItem && hasUserPermission(item.layer.api?.collectionName!, "update", item)) || item.layer.customEditLink) && <li>
|
||||
<a className="!tw-text-base-content tw-cursor-pointer" onClick={(e) => {
|
||||
item.layer?.customEditLink && navigate(item.layer.customEditLink);
|
||||
!item.layer?.customEditLink && openEditPopup(e);
|
||||
}}>
|
||||
<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>}
|
||||
|
||||
{item.layer.api.deleteItem && hasUserPermission(item.layer.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>
|
||||
:
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fillRule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clipRule="evenodd" />
|
||||
</svg>}
|
||||
</a>
|
||||
</li>}
|
||||
</ul>
|
||||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
<DialogModal isOpened={modalOpen} title="Are you sure?" showCloseButton={false} onClose={ () => (setModalOpen(false)) }>
|
||||
<span>Do you want to delete <b>{item.name}</b>?</span>
|
||||
<div className="tw-grid">
|
||||
<div className="tw-flex tw-justify-between">
|
||||
<label className="tw-btn tw-mt-4 tw-btn-error" onClick={removeItemFromMap}>Yes</label>
|
||||
<label className="tw-btn tw-mt-4" onClick={() => setModalOpen(false)}>No</label>
|
||||
</div>
|
||||
<DialogModal isOpened={modalOpen} title="Are you sure?" showCloseButton={false} onClose={() => (setModalOpen(false))} >
|
||||
<div onClick={(e) => e.stopPropagation()} >
|
||||
<span>Do you want to delete <b>{item.name}</b>?</span>
|
||||
<div className="tw-grid">
|
||||
<div className="tw-flex tw-justify-between" >
|
||||
<label className="tw-btn tw-mt-4 tw-btn-error" onClick={(e) => { deleteCallback(e); setModalOpen(false); }}>Yes</label>
|
||||
<label className="tw-btn tw-mt-4" onClick={() => setModalOpen(false)}>No</label>
|
||||
</div>
|
||||
</DialogModal>
|
||||
</div>
|
||||
</div>
|
||||
</DialogModal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -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<boolean>(false);
|
||||
const removeItem = useRemoveItem();
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
const [infoExpanded, setInfoExpanded] = useState<Boolean>(false);
|
||||
|
||||
const handleEdit = (event: React.MouseEvent<HTMLElement>) => {
|
||||
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<HTMLElement>) => {
|
||||
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 (
|
||||
<LeafletPopup ref={ref} maxHeight={377} minWidth={275} maxWidth={275} autoPanPadding={[20, 80]}>
|
||||
<div className='tw-bg-base-100 tw-text-base-content'>
|
||||
<HeaderView item={props.item} setItemFormPopup={props.setItemFormPopup} />
|
||||
<HeaderView api={props.item.api} item={props.item} editCallback={handleEdit} deleteCallback={handleDelete} />
|
||||
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
||||
{props.children ?
|
||||
|
||||
@ -48,8 +86,8 @@ export const ItemViewPopup = React.forwardRef((props: ItemViewPopupProps, ref: a
|
||||
<p className="!tw-my-0 tw-min-h-[21px] tw-font-bold tw-cursor-pointer tw-text-gray-500" onClick={() => setInfoExpanded(true)}>ⓘ</p>
|
||||
}
|
||||
<div className='tw-grow'></div>
|
||||
{ //** <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="tw-place-self-end tw-w-4 tw-h-4 tw-mb-1 tw-cursor-pointer"><path strokeLinecap="round" strokeLinejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" /></svg> */
|
||||
}
|
||||
{ //** <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="tw-place-self-end tw-w-4 tw-h-4 tw-mb-1 tw-cursor-pointer"><path strokeLinecap="round" strokeLinejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" /></svg> */
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</LeafletPopup>
|
||||
|
||||
@ -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() {
|
||||
<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={() => setActiveTab(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" >
|
||||
<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'>
|
||||
<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 (
|
||||
|
||||
<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)}>
|
||||
<HeaderView item={i} />
|
||||
<HeaderView loading={loading} item={i} api={i.layer?.api} editCallback={() => navigate("/edit-item/"+i.id)}></HeaderView>
|
||||
|
||||
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
||||
<TextView truncate item={i} />
|
||||
</div>
|
||||
@ -206,7 +216,7 @@ export function OverlayItemProfile() {
|
||||
</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={() => setActiveTab(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">
|
||||
<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">
|
||||
<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 => {
|
||||
|
||||
@ -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<HTMLFormElement>(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 (
|
||||
|
||||
|
||||
<div key={k} 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-p-4 tw-mb-4 tw-h-fit' onClick={() => navigate(url + getValue(i,parameterField))}>
|
||||
|
||||
<div className='tw-grid tw-grid-cols-6 tw-pb-2'>
|
||||
<div className='tw-col-span-5'>
|
||||
<div className="tw-flex tw-flex-row">{
|
||||
getValue(i, itemImageField) ?
|
||||
<div className="tw-w-10 tw-min-w-[2.5em] tw-rounded-full">
|
||||
<img className="tw-rounded-full" src={`${assetsApi.url}${getValue(i, itemImageField)}?width=80&height=80`} />
|
||||
</div>
|
||||
:
|
||||
""
|
||||
}
|
||||
<b className={`tw-text-xl tw-font-bold ${getValue(i, itemImageField) ? "tw-ml-2 tw-mt-1" : ""}`}>{getValue(i, itemNameField)}</b>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className='tw-col-span-1'>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
||||
<TextView truncate item={i} itemTextField={itemTextField} />
|
||||
</div>
|
||||
<div key={k} 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-p-4 tw-mb-4 tw-h-fit' onClick={() => navigate(url + getValue(i, parameterField))}>
|
||||
<HeaderView loading={loading} item={i} api={api} itemAvatarField={itemImageField} itemNameField={itemNameField} editCallback={() => navigate("/edit-item/"+i.id)} deleteCallback={()=>deleteItem(i)}></HeaderView>
|
||||
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
||||
<TextView truncate item={i} itemTextField={itemTextField} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
|
||||
@ -154,7 +153,7 @@ export const ItemsIndexPage = ({ api, url, parameterField, breadcrumbs, itemName
|
||||
}
|
||||
{addItemPopupType == "project" ?
|
||||
|
||||
<form ref={tabRef} autoComplete='off' onSubmit={e => submitNewItem(e, addItemPopupType)} >
|
||||
<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-p-6 tw-mb-10'>
|
||||
<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={() => {
|
||||
@ -171,7 +170,7 @@ export const ItemsIndexPage = ({ api, url, parameterField, breadcrumbs, itemName
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<PlusButton triggerAction={() => {setAddItemPopupType("project"); scroll();}} color={'#777'} collection='items'/>
|
||||
<PlusButton triggerAction={() => { setAddItemPopupType("project"); scroll(); }} color={'#777'} collection='items' />
|
||||
{children}
|
||||
</main>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user