mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
updated item profiles
This commit is contained in:
parent
34dac6ec5d
commit
63fb0d3fd0
@ -9,7 +9,7 @@ export function ActionButton({ item, triggerAddButton, triggerItemSelected, exis
|
|||||||
triggerAddButton?: any,
|
triggerAddButton?: any,
|
||||||
triggerItemSelected?: any,
|
triggerItemSelected?: any,
|
||||||
existingRelations: Item[],
|
existingRelations: Item[],
|
||||||
itemType: string;
|
itemType?: string;
|
||||||
color: string,
|
color: string,
|
||||||
collection?: string,
|
collection?: string,
|
||||||
item: Item
|
item: Item
|
||||||
@ -19,7 +19,7 @@ export function ActionButton({ item, triggerAddButton, triggerItemSelected, exis
|
|||||||
|
|
||||||
const items = useItems();
|
const items = useItems();
|
||||||
|
|
||||||
const filterdItems = items.filter(i => i.layer?.itemType.name == itemType).filter(i => !existingRelations.some(s => s.id == i.id)).filter(i => i.id != item.id)
|
const filterdItems = items.filter(i => !itemType || i.layer?.itemType.name == itemType).filter(i => !existingRelations.some(s => s.id == i.id)).filter(i => i.id != item.id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ export function ActionButton({ item, triggerAddButton, triggerItemSelected, exis
|
|||||||
</svg>
|
</svg>
|
||||||
</button>}
|
</button>}
|
||||||
</div>
|
</div>
|
||||||
<DialogModal title={"Select"} isOpened={modalOpen} onClose={() => (setModalOpen(false))} className="!tw-max-w-2xl ">
|
<DialogModal title={"Select"} isOpened={modalOpen} onClose={() => (setModalOpen(false))} className="!tw-max-w-2xl tw-bg-base-200">
|
||||||
<div className='tw-grid tw-grid-cols-1 sm:tw-grid-cols-2 md:tw-grid-cols-2 lg:tw-grid-cols-2 xl:tw-grid-cols-2'>
|
<div className='tw-grid tw-grid-cols-1 sm:tw-grid-cols-2 md:tw-grid-cols-2 lg:tw-grid-cols-2 xl:tw-grid-cols-2'>
|
||||||
{filterdItems.map(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-4 tw-mb-4 tw-h-fit' onClick={() => { triggerItemSelected(i.id); setModalOpen(false) }}>
|
{filterdItems.map(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-4 tw-mb-4 tw-h-fit' onClick={() => { triggerItemSelected(i.id); setModalOpen(false) }}>
|
||||||
<HeaderView item={i} hideMenu></HeaderView>
|
<HeaderView item={i} hideMenu></HeaderView>
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export function LinkedItemsHeaderView({ item, unlinkCallback, itemNameField, ite
|
|||||||
<div className='tw-col-span-1' onClick={(e) => e.stopPropagation()}>
|
<div className='tw-col-span-1' onClick={(e) => e.stopPropagation()}>
|
||||||
{unlinkPermission &&
|
{unlinkPermission &&
|
||||||
<div className="tw-dropdown tw-dropdown-bottom">
|
<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">
|
<label tabIndex={0} className=" 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">
|
<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" />
|
<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>
|
</svg>
|
||||||
|
|||||||
@ -2,12 +2,12 @@ import { MapOverlayPage } from '../Templates'
|
|||||||
import { useAddItem, useItems, useRemoveItem, useUpdateItem } from '../Map/hooks/useItems'
|
import { useAddItem, useItems, useRemoveItem, useUpdateItem } from '../Map/hooks/useItems'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { Item } from '../../types';
|
import { Item, Tag } from '../../types';
|
||||||
import { useMap } from 'react-leaflet';
|
import { useMap } from 'react-leaflet';
|
||||||
import { LatLng } from 'leaflet';
|
import { LatLng } from 'leaflet';
|
||||||
import { PopupStartEndInput, StartEndView, TextView } from '../Map';
|
import { PopupStartEndInput, StartEndView, TextView } from '../Map';
|
||||||
import { useAddTag, useTags } from '../Map/hooks/useTags';
|
import { useAddTag, useTags } from '../Map/hooks/useTags';
|
||||||
import { useFilterTags, useResetFilterTags } from '../Map/hooks/useFilter';
|
import { useAddFilterTag, useFilterTags, useResetFilterTags } from '../Map/hooks/useFilter';
|
||||||
import { useHasUserPermission } from '../Map/hooks/usePermissions';
|
import { useHasUserPermission } from '../Map/hooks/usePermissions';
|
||||||
import { TextAreaInput, TextInput } from '../Input';
|
import { TextAreaInput, TextInput } from '../Input';
|
||||||
import { hashTagRegex } from '../../Utils/HashTagRegex';
|
import { hashTagRegex } from '../../Utils/HashTagRegex';
|
||||||
@ -21,6 +21,8 @@ import { HeaderView } from '../Map/Subcomponents/ItemPopupComponents/HeaderView'
|
|||||||
import { useSelectPosition, useSetSelectPosition } from '../Map/hooks/useSelectPosition';
|
import { useSelectPosition, useSetSelectPosition } from '../Map/hooks/useSelectPosition';
|
||||||
import { useClusterRef } from '../Map/hooks/useClusterRef';
|
import { useClusterRef } from '../Map/hooks/useClusterRef';
|
||||||
import { useLeafletRefs } from '../Map/hooks/useLeafletRefs';
|
import { useLeafletRefs } from '../Map/hooks/useLeafletRefs';
|
||||||
|
import { getValue } from '../../Utils/GetValue';
|
||||||
|
import { TagView } from '../Templates/TagView';
|
||||||
|
|
||||||
export function OverlayItemProfile() {
|
export function OverlayItemProfile() {
|
||||||
|
|
||||||
@ -29,6 +31,8 @@ export function OverlayItemProfile() {
|
|||||||
const [activeTab, setActiveTab] = useState<number>(1);
|
const [activeTab, setActiveTab] = useState<number>(1);
|
||||||
const [addItemPopupType, setAddItemPopupType] = useState<string>("");
|
const [addItemPopupType, setAddItemPopupType] = useState<string>("");
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [offers, setOffers] = useState<Array<Tag>>([]);
|
||||||
|
const [needs, setNeeds] = useState<Array<Tag>>([]);
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const items = useItems();
|
const items = useItems();
|
||||||
@ -49,6 +53,8 @@ export function OverlayItemProfile() {
|
|||||||
const setSelectPosition = useSetSelectPosition();
|
const setSelectPosition = useSetSelectPosition();
|
||||||
const clusterRef = useClusterRef();
|
const clusterRef = useClusterRef();
|
||||||
const leafletRefs = useLeafletRefs();
|
const leafletRefs = useLeafletRefs();
|
||||||
|
const addFilterTag = useAddFilterTag();
|
||||||
|
|
||||||
|
|
||||||
const tabRef = useRef<HTMLFormElement>(null);
|
const tabRef = useRef<HTMLFormElement>(null);
|
||||||
|
|
||||||
@ -76,43 +82,60 @@ export function OverlayItemProfile() {
|
|||||||
const item = items.find(i => i.id === itemId);
|
const item = items.find(i => i.id === itemId);
|
||||||
item && setItem(item);
|
item && setItem(item);
|
||||||
console.log(item);
|
console.log(item);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}, [items,location])
|
|
||||||
|
|
||||||
|
}, [items, location])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setOffers([]);
|
||||||
|
setNeeds([]);
|
||||||
|
setRelations([]);
|
||||||
|
|
||||||
|
item.layer?.itemOffersField && getValue(item, item.layer.itemOffersField).map(o => {
|
||||||
|
const tag = tags.find(t => t.id === o.tags_id);
|
||||||
|
tag && setOffers(current => [...current, tag])
|
||||||
|
})
|
||||||
|
item.layer?.itemNeedsField && getValue(item, item.layer.itemNeedsField).map(n => {
|
||||||
|
const tag = tags.find(t => t.id === n.tags_id);
|
||||||
|
tag && setNeeds(current => [...current, tag])
|
||||||
|
})
|
||||||
|
item.relations?.map(r => {
|
||||||
|
const item = items.find(i => i.id == r.related_items_id)
|
||||||
|
item && setRelations(current => [...current, item])
|
||||||
|
})
|
||||||
|
|
||||||
|
}, [item,items])
|
||||||
|
|
||||||
}, [item])
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (item) {
|
if (item) {
|
||||||
if(item.position) {
|
if (item.position) {
|
||||||
const marker = Object.entries(leafletRefs).find(r => r[1].item == item)?.[1].marker;
|
const marker = Object.entries(leafletRefs).find(r => r[1].item == item)?.[1].marker;
|
||||||
marker && clusterRef.hasLayer(marker) && clusterRef?.zoomToShowLayer(marker, () => {
|
marker && clusterRef.hasLayer(marker) && clusterRef?.zoomToShowLayer(marker, () => {
|
||||||
const bounds = map.getBounds();
|
const bounds = map.getBounds();
|
||||||
const x = bounds.getEast() - bounds.getWest();
|
const x = bounds.getEast() - bounds.getWest();
|
||||||
map.setView(new LatLng(item?.position?.coordinates[1]!, item?.position?.coordinates[0]! + x / 4), undefined, {duration: 1});
|
map.setView(new LatLng(item?.position?.coordinates[1]!, item?.position?.coordinates[0]! + x / 4), undefined, { duration: 1 });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
const parent = getFirstAncestor(item);
|
const parent = getFirstAncestor(item);
|
||||||
|
|
||||||
const marker = Object.entries(leafletRefs).find(r => r[1].item == parent)?.[1].marker;
|
const marker = Object.entries(leafletRefs).find(r => r[1].item == parent)?.[1].marker;
|
||||||
marker && clusterRef.hasLayer(marker) && clusterRef?.zoomToShowLayer(marker, () => {
|
marker && clusterRef.hasLayer(marker) && clusterRef?.zoomToShowLayer(marker, () => {
|
||||||
const bounds = map.getBounds();
|
const bounds = map.getBounds();
|
||||||
const x = bounds.getEast() - bounds.getWest();
|
const x = bounds.getEast() - bounds.getWest();
|
||||||
map.setView(new LatLng(parent?.position?.coordinates[1]!, parent?.position?.coordinates[0]! + x / 4), undefined, {duration: 1});
|
map.setView(new LatLng(parent?.position?.coordinates[1]!, parent?.position?.coordinates[0]! + x / 4), undefined, { duration: 1 });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [item])
|
}, [item])
|
||||||
|
|
||||||
|
|
||||||
const getFirstAncestor = (item: Item): Item | undefined => {
|
const getFirstAncestor = (item: Item): Item | undefined => {
|
||||||
const parent = items.find(i => i.id === item.parent);
|
const parent = items.find(i => i.id === item.parent);
|
||||||
if (parent?.parent) {
|
if (parent?.parent) {
|
||||||
@ -121,8 +144,8 @@ export function OverlayItemProfile() {
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -133,16 +156,6 @@ export function OverlayItemProfile() {
|
|||||||
}, [location])
|
}, [location])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
setRelations([]);
|
|
||||||
item.relations?.map(r => {
|
|
||||||
const item = items.find(i => i.id == r.related_items_id)
|
|
||||||
item && setRelations(current => [...current, item])
|
|
||||||
})
|
|
||||||
}, [item, activeTab])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
item && item.user_created && hasUserPermission("items", "update", item) && setUpdatePermission(true);
|
item && item.user_created && hasUserPermission("items", "update", item) && setUpdatePermission(true);
|
||||||
}, [item])
|
}, [item])
|
||||||
@ -254,15 +267,13 @@ export function OverlayItemProfile() {
|
|||||||
navigate("/");
|
navigate("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{item &&
|
{item &&
|
||||||
<MapOverlayPage key ={item.id} 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-0 sm:!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'}`}>
|
<MapOverlayPage key={item.id} 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-0 sm:!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)} setPositionCallback={()=>{map.closePopup();setSelectPosition(item); navigate("/")}} big truncateSubname={false}/>
|
<HeaderView api={item.layer?.api} item={item} deleteCallback={handleDelete} editCallback={() => navigate("/edit-item/" + item.id)} setPositionCallback={() => { map.closePopup(); setSelectPosition(item); navigate("/") }} big truncateSubname={false} />
|
||||||
|
|
||||||
<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">
|
<div role="tablist" className="tw-tabs tw-tabs-lifted tw-mt-2 tw-mb-2">
|
||||||
@ -271,107 +282,72 @@ export function OverlayItemProfile() {
|
|||||||
<TextView item={item} />
|
<TextView item={item} />
|
||||||
</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="Projects" checked={activeTab == 2 && true} onChange={() => updateActiveTab(2)} />
|
{item.layer?.itemType.offers_and_needs &&
|
||||||
<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.layer?.itemType.name == '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 className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
|
||||||
<TextView truncate item={i} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
)
|
|
||||||
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>
|
|
||||||
</div>
|
|
||||||
</form> : <></>
|
|
||||||
}
|
|
||||||
{updatePermission && <ActionButton collection="items" item={item} existingRelations={relations} itemType={"project"} triggerItemSelected={linkItem} triggerAddButton={() => { setAddItemPopupType("project"); scroll() }} color={item.color}></ActionButton>}
|
|
||||||
|
|
||||||
|
<input type="radio" name="my_tabs_2" role="tab" className="tw-tab tw-min-w-[10em] [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]" aria-label="Offers & Needs" 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-268px)] tw-overflow-y-auto fade tw-pt-4 tw-pb-1" >
|
||||||
|
<div className='tw-h-full'>
|
||||||
|
<div className='tw-grid tw-grid-cols-1'>
|
||||||
|
{
|
||||||
|
offers.length > 0 ?
|
||||||
|
<div className='tw-col-span-1'>
|
||||||
|
<h3 className='-tw-mb-2'>Offers</h3>
|
||||||
|
< div className='tw-flex tw-flex-wrap tw-mb-4'>
|
||||||
|
{
|
||||||
|
offers.map(o => <TagView key={o?.id} tag={o} onClick={() => {
|
||||||
|
console.log(o);
|
||||||
|
addFilterTag(o)
|
||||||
|
}} />)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div> : ""
|
||||||
|
}
|
||||||
|
{
|
||||||
|
needs.length > 0 ?
|
||||||
|
<div className='tw-col-span-1'>
|
||||||
|
<h3 className='-tw-mb-2 tw-col-span-1'>Needs</h3>
|
||||||
|
< div className='tw-flex tw-flex-wrap tw-mb-4'>
|
||||||
|
{
|
||||||
|
needs.map(n => <TagView key={n?.id} tag={n} onClick={() => addFilterTag(n)} />)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div> : ""
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</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-1 2xl:tw-grid-cols-2'>
|
|
||||||
{relations && relations.map(i => {
|
|
||||||
if (i.layer?.itemType.name == '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'>
|
{item.layer?.itemType.relations &&
|
||||||
<StartEndView item={i}></StartEndView>
|
<>
|
||||||
<TextView truncate item={i} />
|
<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="Relations" checked={activeTab == 7 && true} onChange={() => updateActiveTab(7)} />
|
||||||
|
<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 =>
|
||||||
|
|
||||||
|
|
||||||
|
<div key={i.id} className='tw-cursor-pointer tw-card tw-bg-base-200 tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl 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'>
|
||||||
|
<TextView truncate item={i} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
)
|
|
||||||
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-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={() => {
|
{updatePermission && <ActionButton collection="items" item={item} existingRelations={relations} triggerItemSelected={linkItem} color={item.color}></ActionButton>}
|
||||||
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>
|
|
||||||
</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>
|
||||||
</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="Community" 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 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.layer?.itemType.name == 'user') 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'>
|
|
||||||
<TextView truncate item={i} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
else return null
|
|
||||||
})}
|
|
||||||
{updatePermission && <ActionButton collection="items" item={item} existingRelations={relations} itemType={"user"} triggerItemSelected={linkItem} color={item.color}></ActionButton>}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -10,12 +10,17 @@ import { hashTagRegex } from '../../Utils/HashTagRegex';
|
|||||||
import { useAddTag, useTags } from '../Map/hooks/useTags';
|
import { useAddTag, useTags } from '../Map/hooks/useTags';
|
||||||
import { randomColor } from '../../Utils/RandomColor';
|
import { randomColor } from '../../Utils/RandomColor';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import { Item } from '../../types';
|
import { Item, Tag } from '../../types';
|
||||||
import { MapOverlayPage } from '../Templates';
|
import { MapOverlayPage } from '../Templates';
|
||||||
|
|
||||||
import { AvatarWidget } from './AvatarWidget';
|
import { AvatarWidget } from './AvatarWidget';
|
||||||
import { encodeTag } from '../../Utils/FormatTags';
|
import { encodeTag } from '../../Utils/FormatTags';
|
||||||
import { useLayers } from '../Map/hooks/useLayers';
|
import { useLayers } from '../Map/hooks/useLayers';
|
||||||
|
import { TagsWidget } from './TagsWidget';
|
||||||
|
import { LinkedItemsHeaderView } from './LinkedItemsHeaderView';
|
||||||
|
import { TextView } from '../Map/Subcomponents/ItemPopupComponents/TextView';
|
||||||
|
import { ActionButton } from './ActionsButton';
|
||||||
|
import { useHasUserPermission } from '../Map/hooks/usePermissions';
|
||||||
|
|
||||||
|
|
||||||
export function OverlayItemProfileSettings() {
|
export function OverlayItemProfileSettings() {
|
||||||
@ -26,6 +31,12 @@ export function OverlayItemProfileSettings() {
|
|||||||
const [text, setText] = useState<string>("");
|
const [text, setText] = useState<string>("");
|
||||||
const [image, setImage] = useState<string>("");
|
const [image, setImage] = useState<string>("");
|
||||||
const [color, setColor] = useState<string>("");
|
const [color, setColor] = useState<string>("");
|
||||||
|
const [offers, setOffers] = useState<Array<Tag>>([]);
|
||||||
|
const [needs, setNeeds] = useState<Array<Tag>>([]);
|
||||||
|
const [updatePermission, setUpdatePermission] = useState<boolean>(false);
|
||||||
|
const [relations, setRelations] = useState<Array<Item>>([]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState<number>(1);
|
const [activeTab, setActiveTab] = useState<number>(1);
|
||||||
@ -34,6 +45,7 @@ export function OverlayItemProfileSettings() {
|
|||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
|
|
||||||
|
const hasUserPermission = useHasUserPermission();
|
||||||
|
|
||||||
const updateItem = useUpdateItem();
|
const updateItem = useUpdateItem();
|
||||||
const addItem = useAddItem();
|
const addItem = useAddItem();
|
||||||
@ -52,10 +64,28 @@ export function OverlayItemProfileSettings() {
|
|||||||
const itemId = location.pathname.split("/")[2];
|
const itemId = location.pathname.split("/")[2];
|
||||||
const item = items.find(i => i.id === itemId);
|
const item = items.find(i => i.id === itemId);
|
||||||
item && setItem(item);
|
item && setItem(item);
|
||||||
!item && setItem({id: crypto.randomUUID(), name: user ? user.first_name : "", text: ""})
|
!item && setItem({ id: crypto.randomUUID(), name: user ? user.first_name : "", text: "" })
|
||||||
|
|
||||||
}, [location, items, activeTab])
|
}, [location, items, activeTab])
|
||||||
|
|
||||||
|
const updateActiveTab = (id: number) => {
|
||||||
|
setActiveTab(id);
|
||||||
|
|
||||||
|
let params = new URLSearchParams(window.location.search);
|
||||||
|
let urlTab = params.get("tab");
|
||||||
|
if (!urlTab?.includes(id.toString()))
|
||||||
|
params.set("tab", `${id ? id : ""}`)
|
||||||
|
window.history.pushState('', '', "?" + params.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let params = new URLSearchParams(location.search);
|
||||||
|
let urlTab = params.get("tab");
|
||||||
|
urlTab ? setActiveTab(Number(urlTab)) : setActiveTab(1);
|
||||||
|
}, [location])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (item.layer?.itemColorField) setColor(getValue(item, item.layer?.itemColorField));
|
if (item.layer?.itemColorField) setColor(getValue(item, item.layer?.itemColorField));
|
||||||
else setColor(item.layer?.markerDefaultColor || "#3D3846")
|
else setColor(item.layer?.markerDefaultColor || "#3D3846")
|
||||||
@ -65,70 +95,116 @@ export function OverlayItemProfileSettings() {
|
|||||||
setSubname(item?.subname ? item.subname : "");
|
setSubname(item?.subname ? item.subname : "");
|
||||||
setText(item?.text ? item.text : "");
|
setText(item?.text ? item.text : "");
|
||||||
setImage(item?.image ? item?.image : "");
|
setImage(item?.image ? item?.image : "");
|
||||||
|
setOffers([]);
|
||||||
|
setNeeds([]);
|
||||||
|
item?.offers?.map(o => {
|
||||||
|
const offer = tags.find(t => t.id === o.tags_id);
|
||||||
|
offer && setOffers(current => [...current, offer])
|
||||||
|
})
|
||||||
|
item?.needs?.map(o => {
|
||||||
|
const need = tags.find(t => t.id === o.tags_id);
|
||||||
|
need && setNeeds(current => [...current, need])
|
||||||
|
})
|
||||||
|
setRelations([]);
|
||||||
|
item.relations?.map(r => {
|
||||||
|
const item = items.find(i => i.id == r.related_items_id)
|
||||||
|
item && setRelations(current => [...current, item])
|
||||||
|
})
|
||||||
|
item && item.user_created && hasUserPermission("items", "update", item) && setUpdatePermission(true);
|
||||||
|
|
||||||
}, [item])
|
}, [item])
|
||||||
|
|
||||||
|
|
||||||
const onUpdateItem = async () => {
|
const onUpdateItem = async () => {
|
||||||
let changedItem = {} as Item;
|
let changedItem = {} as Item;
|
||||||
|
|
||||||
|
let offer_updates : Array<any> = [];
|
||||||
|
//check for new offers
|
||||||
|
offers.map(o => {
|
||||||
|
const existingOffer = item?.offers?.find(t => t.tags_id === o.id)
|
||||||
|
existingOffer && offer_updates.push(existingOffer.id)
|
||||||
|
if(!existingOffer && !tags.some(t => t.id === o.id)) addTag({...o,offer_or_need: true})
|
||||||
|
!existingOffer && offer_updates.push({items_id: item?.id, tags_id: o.id})
|
||||||
|
});
|
||||||
|
|
||||||
|
let needs_updates : Array<any> = [];
|
||||||
|
|
||||||
|
needs.map(n => {
|
||||||
|
const existingNeed = user?.needs.find(t => t.tags_id === n.id)
|
||||||
|
existingNeed && needs_updates.push(existingNeed.id)
|
||||||
|
!existingNeed && needs_updates.push({items_id: item?.id, tags_id: n.id})
|
||||||
|
!existingNeed && !tags.some(t => t.id === n.id) && addTag({...n,offer_or_need: true})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
changedItem = { id: id, name: name, subname: subname, text: text, color: color, position: item.position, ...image.length > 10 && { image: image }};
|
|
||||||
|
changedItem = { id: id, name: name, subname: subname, text: text, color: color, position: item.position, ...image.length > 10 && { image: image }, ... offers.length > 0 && {offers: offer_updates}, ... needs.length > 0 && {needs: needs_updates} };
|
||||||
// update profile item in current state
|
// update profile item in current state
|
||||||
//const item = items.find(i => i.layer?.itemOwnerField && getValue(i, i.layer?.itemOwnerField).id === id);
|
|
||||||
|
let offers_state : Array<any> = [];
|
||||||
|
let needs_state : Array<any> = [];
|
||||||
|
|
||||||
|
await offers.map(o => {
|
||||||
|
offers_state.push({items_id: item?.id, tags_id: o.id})
|
||||||
|
});
|
||||||
|
|
||||||
|
await needs.map(n => {
|
||||||
|
needs_state.push({items_id: item?.id, tags_id: n.id})
|
||||||
|
});
|
||||||
|
|
||||||
|
changedItem = {... changedItem, offers: offers_state, needs: needs_state};
|
||||||
|
|
||||||
|
|
||||||
// if (item && item.layer && item.layer.itemOwnerField) item[item.layer.itemOwnerField] = {... changedUser, offers: offer_state, needs: needs_state};
|
|
||||||
// add new hashtags from profile text
|
|
||||||
text.toLocaleLowerCase().match(hashTagRegex)?.map(tag => {
|
text.toLocaleLowerCase().match(hashTagRegex)?.map(tag => {
|
||||||
if (!tags.find((t) => t.name.toLocaleLowerCase() === tag.slice(1).toLocaleLowerCase())) {
|
if (!tags.find((t) => t.name.toLocaleLowerCase() === tag.slice(1).toLocaleLowerCase())) {
|
||||||
addTag({ id: crypto.randomUUID(), name: encodeTag(tag.slice(1).toLocaleLowerCase()), color: randomColor()})
|
addTag({ id: crypto.randomUUID(), name: encodeTag(tag.slice(1).toLocaleLowerCase()), color: randomColor() })
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
console.log(item.layer);
|
console.log(item.layer);
|
||||||
|
|
||||||
|
|
||||||
if(item.layer) {item?.layer?.api?.updateItem && toast.promise(
|
|
||||||
item?.layer?.api?.updateItem(changedItem),
|
|
||||||
{
|
|
||||||
pending: 'updating Item ...',
|
|
||||||
success: 'Item updated',
|
|
||||||
error: {
|
|
||||||
render({ data }) {
|
|
||||||
return `${data}`
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(() => item && updateItem({...item, ...changedItem}))
|
|
||||||
.then(() => {
|
|
||||||
setLoading(false);
|
|
||||||
navigate("/item/"+item.id)});
|
|
||||||
|
|
||||||
}
|
if (item.layer) {
|
||||||
else {
|
item?.layer?.api?.updateItem && toast.promise(
|
||||||
const layer = layers.find(l => l.itemType.name == "user")
|
item?.layer?.api?.updateItem(changedItem),
|
||||||
layer?.api?.createItem && toast.promise(
|
{
|
||||||
layer?.api?.createItem(changedItem),
|
pending: 'updating Item ...',
|
||||||
{
|
success: 'Item updated',
|
||||||
pending: 'updating Item ...',
|
error: {
|
||||||
success: 'Item updated',
|
render({ data }) {
|
||||||
error: {
|
return `${data}`
|
||||||
render({ data }) {
|
|
||||||
return `${data}`
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
.then(() => item && addItem({...item, ...changedItem, layer: layer, user_created: user, type: layer.itemType}))
|
})
|
||||||
.then(() => {
|
.then(() => item && updateItem({ ...item, ...changedItem }))
|
||||||
setLoading(false);
|
.then(() => {
|
||||||
navigate("/")});
|
setLoading(false);
|
||||||
console.log({...item, ...changedItem, layer: layer, user_created: user, type: "User"});
|
navigate("/item/" + item.id)
|
||||||
|
});
|
||||||
}
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const layer = layers.find(l => l.itemType.name == "user")
|
||||||
|
layer?.api?.createItem && toast.promise(
|
||||||
|
layer?.api?.createItem(changedItem),
|
||||||
|
{
|
||||||
|
pending: 'updating Item ...',
|
||||||
|
success: 'Item updated',
|
||||||
|
error: {
|
||||||
|
render({ data }) {
|
||||||
|
return `${data}`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(() => item && addItem({ ...item, ...changedItem, layer: layer, user_created: user, type: layer.itemType }))
|
||||||
|
.then(() => {
|
||||||
|
setLoading(false);
|
||||||
|
navigate("/")
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -136,8 +212,8 @@ export function OverlayItemProfileSettings() {
|
|||||||
<MapOverlayPage backdrop className='tw-mx-4 tw-mt-4 tw-mb-12 tw-overflow-x-hidden tw-max-h-[calc(100dvh-96px)] !tw-h-[calc(100dvh-96px)] tw-w-[calc(100%-32px)] md:tw-w-[calc(50%-32px)] tw-max-w-3xl !tw-left-auto tw-top-0 tw-bottom-0'>
|
<MapOverlayPage backdrop className='tw-mx-4 tw-mt-4 tw-mb-12 tw-overflow-x-hidden tw-max-h-[calc(100dvh-96px)] !tw-h-[calc(100dvh-96px)] tw-w-[calc(100%-32px)] md:tw-w-[calc(50%-32px)] tw-max-w-3xl !tw-left-auto tw-top-0 tw-bottom-0'>
|
||||||
<div className='tw-flex tw-flex-col tw-h-full'>
|
<div className='tw-flex tw-flex-col tw-h-full'>
|
||||||
<div className="tw-flex">
|
<div className="tw-flex">
|
||||||
<AvatarWidget avatar={image} setAvatar={setImage}/>
|
<AvatarWidget avatar={image} setAvatar={setImage} />
|
||||||
<ColorPicker color={color? color : "#3D3846"} onChange={setColor} className={"-tw-left-6 tw-top-14 -tw-mr-6"} />
|
<ColorPicker color={color ? color : "#3D3846"} onChange={setColor} className={"-tw-left-6 tw-top-14 -tw-mr-6"} />
|
||||||
<div className='tw-grow tw-mr-4'>
|
<div className='tw-grow tw-mr-4'>
|
||||||
<TextInput placeholder="Name" defaultValue={item?.name ? item.name : ""} updateFormValue={(v) => setName(v)} containerStyle='tw-grow tw-input-md' />
|
<TextInput placeholder="Name" defaultValue={item?.name ? item.name : ""} updateFormValue={(v) => setName(v)} containerStyle='tw-grow tw-input-md' />
|
||||||
<TextInput placeholder="Subtitle" defaultValue={item?.subname ? item.subname : ""} updateFormValue={(v) => setSubname(v)} containerStyle='tw-grow tw-input-sm tw-px-4 tw-mt-1' />
|
<TextInput placeholder="Subtitle" defaultValue={item?.subname ? item.subname : ""} updateFormValue={(v) => setSubname(v)} containerStyle='tw-grow tw-input-sm tw-px-4 tw-mt-1' />
|
||||||
@ -146,22 +222,27 @@ export function OverlayItemProfileSettings() {
|
|||||||
|
|
||||||
|
|
||||||
<div role="tablist" className="tw-tabs tw-tabs-lifted tw-mt-4">
|
<div role="tablist" className="tw-tabs tw-tabs-lifted tw-mt-4">
|
||||||
<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="Vision" checked={activeTab == 1 && true} onChange={() => setActiveTab(1)} />
|
<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-border-[var(--fallback-bc,oklch(var(--bc)/0.2))] tw-rounded-box tw-h-[calc(100dvh-332px)] tw-min-h-56">
|
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-border-[var(--fallback-bc,oklch(var(--bc)/0.2))] tw-rounded-box tw-h-[calc(100dvh-332px)] tw-min-h-56 tw-border-none">
|
||||||
<TextAreaInput placeholder="My Vision..." defaultValue={item?.text ? item.text : ""} updateFormValue={(v) => {console.log(v);setText(v)}} containerStyle='tw-h-full' inputStyle='tw-h-full tw-border-t-0 tw-rounded-tl-none' />
|
<TextAreaInput placeholder="My Vision..." defaultValue={item?.text ? item.text : ""} updateFormValue={(v) => { console.log(v); setText(v) }} containerStyle='tw-h-full' inputStyle='tw-h-full tw-border-t-0 tw-rounded-tl-none' />
|
||||||
</div>
|
</div>
|
||||||
|
{item.layer?.itemType.offers_and_needs &&
|
||||||
|
<>
|
||||||
|
<input type="radio" name="my_tabs_2" role="tab" className={`tw-tab tw-min-w-[10em] [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]`} aria-label="Offers & Needs" checked={activeTab == 3 && true} onChange={() => updateActiveTab(3)} />
|
||||||
|
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-border-[var(--fallback-bc,oklch(var(--bc)/0.2))] tw-rounded-box tw-h-[calc(100dvh-332px)] tw-min-h-56 tw-border-none">
|
||||||
|
<div className='tw-h-full'>
|
||||||
|
<div className='tw-w-full tw-h-[calc(50%-0.75em)] tw-mb-4'>
|
||||||
|
<TagsWidget defaultTags={offers} onUpdate={(v) => setOffers(v)} placeholder="enter your offers" containerStyle='tw-bg-transparent tw-w-full tw-h-full tw-mt-3 tw-text-xs tw-h-[calc(100%-1rem)] tw-min-h-[5em] tw-pb-2 tw-overflow-auto' />
|
||||||
|
</div>
|
||||||
|
<div className='tw-w-full tw-h-[calc(50%-0.75em)] '>
|
||||||
|
<TagsWidget defaultTags={needs} onUpdate={(v) => setNeeds(v)} placeholder="enter your needs" containerStyle='tw-bg-transparent tw-w-full tw-h-full tw-mt-3 tw-text-xs tw-h-[calc(100%-1rem)] tw-min-h-[5em] tw-pb-2 tw-overflow-auto' />
|
||||||
|
</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="Projects" checked={activeTab == 2 && true} onChange={() => setActiveTab(2)} />
|
|
||||||
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-rounded-box tw-pt-4 tw-h-[calc(100dvh-332px)] tw-min-h-56">
|
|
||||||
</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-border-[var(--fallback-bc,oklch(var(--bc)/0.2))] tw-rounded-box tw-h-[calc(100dvh-332px)] tw-min-h-56">
|
|
||||||
</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={() => setActiveTab(4)} />
|
|
||||||
<div role="tabpanel" className="tw-tab-content tw-bg-base-100 tw-border-[var(--fallback-bc,oklch(var(--bc)/0.2))] tw-rounded-box tw-h-[calc(100dvh-332px)] tw-min-h-56">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="tw-mt-4 tw-mb-4"><button className={loading ? " tw-loading tw-btn-disabled tw-btn tw-btn-primary tw-float-right" : "tw-btn tw-btn-primary tw-float-right"} onClick={() => onUpdateItem()}>Update</button></div>
|
<div className="tw-mt-4 tw-mb-4"><button className={loading ? " tw-loading tw-btn-disabled tw-btn tw-btn-primary tw-float-right" : "tw-btn tw-btn-primary tw-float-right"} onClick={() => onUpdateItem()}>Update</button></div>
|
||||||
|
|||||||
19
src/Components/Templates/DateUserInfo.tsx
Normal file
19
src/Components/Templates/DateUserInfo.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { timeAgo } from "../../Utils/TimeAgo";
|
||||||
|
import { Item } from "../../types";
|
||||||
|
|
||||||
|
export const DateUserInfo = ({ item }: { item: Item }) => {
|
||||||
|
const [infoExpanded, setInfoExpanded] = useState<boolean>(false);
|
||||||
|
return (
|
||||||
|
<div className='tw-flex -tw-mb-1 tw-flex-row tw-mr-2 -tw-mt-2' onClick={(e) => e.stopPropagation()}>
|
||||||
|
|
||||||
|
{
|
||||||
|
infoExpanded ?
|
||||||
|
<p className={`tw-italic tw-min-h-[21px] !tw-my-0 tw-text-gray-500`} onClick={() => setInfoExpanded(false)} >{`${item.date_updated && item.date_updated != item.date_created ? "updated" : "posted"} ${item && item.user_created && item.user_created.first_name ? `by ${item.user_created.first_name}` : ""} ${item.date_updated ? timeAgo(item.date_updated) : timeAgo(item.date_created!)}`}</p>
|
||||||
|
:
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -15,6 +15,7 @@ import { HeaderView } from '../Map/Subcomponents/ItemPopupComponents/HeaderView'
|
|||||||
import { MapOverlayPage } from './MapOverlayPage';
|
import { MapOverlayPage } from './MapOverlayPage';
|
||||||
import { useAddItem, useItems, useRemoveItem } from '../Map/hooks/useItems';
|
import { useAddItem, useItems, useRemoveItem } from '../Map/hooks/useItems';
|
||||||
import { timeAgo } from '../../Utils/TimeAgo';
|
import { timeAgo } from '../../Utils/TimeAgo';
|
||||||
|
import { DateUserInfo } from './DateUserInfo';
|
||||||
|
|
||||||
|
|
||||||
type breadcrumb = {
|
type breadcrumb = {
|
||||||
@ -112,7 +113,7 @@ export const OverlayItemsIndexPage = ({ url, layerName, parameterField, breadcru
|
|||||||
<>
|
<>
|
||||||
|
|
||||||
|
|
||||||
<MapOverlayPage className='tw-rounded-none tw-overflow-y-auto'>
|
<MapOverlayPage className='tw-rounded-none tw-overflow-y-auto tw-to-base-200'>
|
||||||
<div className='tw-h-fit'>
|
<div className='tw-h-fit'>
|
||||||
{breadcrumbs &&
|
{breadcrumbs &&
|
||||||
<div className="tw-text-sm tw-breadcrumbs">
|
<div className="tw-text-sm tw-breadcrumbs">
|
||||||
@ -137,26 +138,7 @@ export const OverlayItemsIndexPage = ({ url, layerName, parameterField, breadcru
|
|||||||
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
||||||
<TextView truncate item={i} itemTextField={itemTextField} />
|
<TextView truncate item={i} itemTextField={itemTextField} />
|
||||||
</div>
|
</div>
|
||||||
<div className='tw-flex -tw-mb-1 tw-flex-row tw-mr-2 -tw-mt-2' onClick={(e) => e.stopPropagation()}>
|
<DateUserInfo item={i}></DateUserInfo>
|
||||||
|
|
||||||
{
|
|
||||||
infoExpanded.get(k) ?
|
|
||||||
<p className={`tw-italic tw-min-h-[21px] !tw-my-0 tw-text-gray-500`} onClick={() => setInfoExpanded(prevMap => {
|
|
||||||
const newMap = new Map(prevMap); // Create a new Map from the previous Map
|
|
||||||
newMap.set(k, false); // Set new or update existing key-value pair
|
|
||||||
return newMap; // Return the new Map to update the state
|
|
||||||
})} >{`${i.date_updated && i.date_updated != i.date_created ? "updated" : "posted"} ${i && i.user_created && i.user_created.first_name ? `by ${i.user_created.first_name}` : ""} ${i.date_updated ? timeAgo(i.date_updated) : timeAgo(i.date_created!)}`}</p>
|
|
||||||
:
|
|
||||||
<p className="!tw-my-0 tw-min-h-[21px] tw-font-bold tw-cursor-pointer tw-text-gray-500" onClick={() => setInfoExpanded(prevMap => {
|
|
||||||
const newMap = new Map(prevMap); // Create a new Map from the previous Map
|
|
||||||
newMap.set(k, true); // Set new or update existing key-value pair
|
|
||||||
return newMap; // Return the new Map to update the state
|
|
||||||
})}>ⓘ</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> */
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user