enhanced offers & needs

This commit is contained in:
Anton Tranelis 2024-02-15 20:13:36 +01:00
parent 1583e55e7e
commit b3b5bbb9ea
7 changed files with 81 additions and 48 deletions

View File

@ -1,4 +1,3 @@
import { useNavigate } from "react-router-dom";
import { useAuth } from "../Auth"
import { Link } from "react-router-dom";
import { toast } from "react-toastify";
@ -8,9 +7,6 @@ import * as React from "react";
export default function NavBar({ appName, nameWidth = 200}: { appName: string, nameWidth?: number }) {
const navigate = useNavigate();
const { isAuthenticated, user, logout, token } = useAuth();

View File

@ -69,9 +69,9 @@ export const Autocomplete = ({ inputProps, suggestions, onSelected, pushFiltered
return (
<div>
<input ref={inputRef} {...inputProps} type="text" onChange={(e) => handleChange(e)} onKeyDown={handleKeyDown}/>
<ul className='tw-absolute tw-z-[4000]'>
<ul className={`tw-absolute tw-z-[4000] ${filteredSuggestions.length>0 && 'tw-bg-base-100 tw-rounded-xl tw-p-2'}`}>
{filteredSuggestions.map((suggestion, index) => (
<li key={index} onClick={() => handleSuggestionClick(suggestion)}><TagView tag={suggestion}></TagView>{index == heighlightedSuggestion && "+"}</li>
<li key={index} onClick={() => handleSuggestionClick(suggestion)}><TagView heighlight={index == heighlightedSuggestion} tag={suggestion}></TagView></li>
))}
</ul>
</div>

View File

@ -10,6 +10,7 @@ import { useAuth } from "../../../Auth";
import { getValue } from "../../../../Utils/GetValue";
import { useAssetApi } from '../../../AppShell/hooks/useAssets'
import DialogModal from "../../../Templates/DialogModal";
import { useNavigate } from "react-router-dom";
@ -31,6 +32,7 @@ export function HeaderView({ item, setItemFormPopup }: {
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;
@ -98,8 +100,11 @@ export function HeaderView({ item, setItemFormPopup }: {
</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") && <li>
<a className="!tw-text-base-content" onClick={openEditPopup}>
{((item.layer.api.updateItem && hasUserPermission(item.layer.api?.collectionName!, "update")) || 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>
@ -107,7 +112,7 @@ export function HeaderView({ item, setItemFormPopup }: {
</li>}
{item.layer.api.deleteItem && hasUserPermission(item.layer.api?.collectionName!, "delete") && <li>
<a className=' !tw-text-error' onClick={openDeleteModal}>
<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">

View File

@ -97,6 +97,15 @@ function useTagsManager(initialTags: Tag[]): {
itemTags.push(tags.find(t => t.name.toLocaleLowerCase() === tag.slice(1).toLocaleLowerCase())!)
}
})
item.layer?.itemOffersField && getValue(item, item.layer.itemOffersField).map(o => {
const offer = tags.find(t=> t.id === o.tags_id)
offer && itemTags.push(offer)
});
item.layer?.itemNeedsField && getValue(item, item.layer.itemNeedsField).map(n => {
const need = tags.find(t=>t.id === n.tags_id);
need && itemTags.push(need);
});
return itemTags
}, [tags]);

View File

@ -1,9 +1,9 @@
import * as React from 'react'
import { CardPage, MapOverlayPage } from '../Templates'
import { MapOverlayPage } from '../Templates'
import { useItems } from '../Map/hooks/useItems'
import { useLocation } from 'react-router-dom'
import { useLocation, useNavigate } from 'react-router-dom'
import { useState } from 'react';
import { Item } from '../../types';
import { Item, UserItem } from '../../types';
import { getValue } from '../../Utils/GetValue';
import { useMap } from 'react-leaflet';
import { LatLng } from 'leaflet';
@ -11,6 +11,8 @@ import { TextView } from '../Map';
import useWindowDimensions from '../Map/hooks/useWindowDimension';
import { TagView } from '../Templates/TagView';
import { useTags } from '../Map/hooks/useTags';
import { useAuth } from '../Auth';
import { useAddFilterTag } from '../Map/hooks/useFilter';
export function OverlayProfile() {
@ -21,8 +23,13 @@ export function OverlayProfile() {
const windowDimension = useWindowDimensions();
const tags = useTags();
const { user } = useAuth();
console.log(item);
const navigate = useNavigate();
const [owner, setOwner] = useState<UserItem>();
const addFilterTag = useAddFilterTag();
@ -30,6 +37,10 @@ export function OverlayProfile() {
const itemId = location.pathname.split("/")[2];
const item = items.find(i => i.id === itemId);
item && setItem(item);
console.log(item);
console.log(user);
item?.layer?.itemOwnerField && setOwner(getValue(item, item.layer?.itemOwnerField));
const bounds = map.getBounds();
const x = bounds.getEast() - bounds.getWest()
if (windowDimension.width > 768)
@ -39,41 +50,53 @@ export function OverlayProfile() {
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-max-w-2xl !tw-left-auto tw-top-0 tw-bottom-0'>
<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-max-w-3xl !tw-left-auto tw-top-0 tw-bottom-0'>
{item &&
<>
<div className="flex flex-row tw-w-full">
<p className="text-4xl">{item.layer?.itemAvatarField && getValue(item, item.layer.itemAvatarField) && <img className='h-20 rounded-full inline' src={`https://api.utopia-lab.org/assets/${getValue(item, item.layer.itemAvatarField)}?width=160&heigth=160`}></img>} {item.layer?.itemNameField && getValue(item, item.layer.itemNameField)}</p>
<div className='tw-flex tw-flex-row'>
<div className="tw-grow">
<p className="text-4xl">{item.layer?.itemAvatarField && getValue(item, item.layer.itemAvatarField) && <img className='h-20 rounded-full inline' src={`https://api.utopia-lab.org/assets/${getValue(item, item.layer.itemAvatarField)}?width=160&heigth=160`}></img>} {item.layer?.itemNameField && getValue(item, item.layer.itemNameField)}</p>
</div>
{owner?.id === user?.id ?
<a className='tw-self-center tw-btn tw-btn-sm tw-mr-4 tw-cursor-pointer' onClick={() => navigate("/profile-settings")}>
<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> : ""
}
</div>
<div className='tw-overflow-y-auto tw-h-full tw-pt-4 fade tw-pb-4'>
{
item.layer?.itemOffersField && getValue(item, item.layer.itemOffersField).length > 0 ?
<>
<h3 className='-tw-mb-2'>Offers</h3>
< div className='tw-flex tw-flex-wrap tw-mb-2'>
{
item.layer?.itemOffersField && getValue(item, item.layer.itemOffersField).map(o => {
const tag = tags.find(t => t.id === o.tags_id);
return (tag ? <TagView key={tag?.id} tag={tag} /> : "")
})
}
</div>
</> : ""
}
{
item.layer?.itemNeedsField && getValue(item, item.layer.itemNeedsField).length > 0 ?
<>
<h3 className='-tw-mb-2'>Needs</h3>
< div className='tw-flex tw-flex-wrap tw-mb-4'>
{
item.layer?.itemNeedsField && getValue(item, item.layer.itemNeedsField).map(o => {
const tag = tags.find(t => t.id === o.tags_id);
return (tag ? <TagView key={tag?.id} tag={tag} /> : "")
})
}
</div>
</> : ""
}
<div className='tw-overflow-y-auto tw-h-full tw-pt-4 fade'>
<div className='tw-grid tw-grid-cols-1 xl:tw-grid-cols-2'>
{
item.layer?.itemOffersField && getValue(item, item.layer.itemOffersField).length > 0 ?
<div className='tw-col-span-1'>
<h3 className='-tw-mb-2'>Offers</h3>
< div className='tw-flex tw-flex-wrap tw-mb-2'>
{
item.layer?.itemOffersField && getValue(item, item.layer.itemOffersField).map(o => {
const tag = tags.find(t => t.id === o.tags_id);
return (tag ? <TagView key={tag?.id} tag={tag} onClick={() => addFilterTag(tag)}/> : "")
})
}
</div>
</div> : ""
}
{
item.layer?.itemNeedsField && getValue(item, item.layer.itemNeedsField).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'>
{
item.layer?.itemNeedsField && getValue(item, item.layer.itemNeedsField).map(o => {
const tag = tags.find(t => t.id === o.tags_id);
return (tag ? <TagView key={tag?.id} tag={tag} onClick={() => addFilterTag(tag)}/> : "")
})
}
</div>
</div> : ""
}
</div>
<TextView item={item} />
</div>
</>

View File

@ -223,7 +223,7 @@ export function OverlayProfileSettings() {
return (
<>
<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-2xl !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">
{!cropping ?

View File

@ -2,11 +2,11 @@ import * as React from 'react'
import { decodeTag } from '../../Utils/FormatTags'
import { Tag } from '../../types'
export const TagView = ({tag} : {tag: Tag}) => {
export const TagView = ({tag, heighlight, onClick} : {tag: Tag, heighlight?: boolean, onClick?: (e)=> void}) => {
return (
// Use your imagination to render suggestions.
<div key={tag.name} className='tw-rounded-2xl tw-text-white tw-p-2 tw-px-4 tw-shadow-xl tw-card tw-h-[2.75em] tw-mt-3 tw-mr-4 tw-cursor-pointer tw-w-fit' style={{ backgroundColor: tag.color ? tag.color : "#666" }}>
<div key={tag.name} onClick={onClick} className={`tw-rounded-2xl tw-text-white tw-p-2 tw-px-4 tw-shadow-xl tw-card tw-h-[2.75em] tw-mt-3 tw-mr-4 tw-cursor-pointer tw-w-fit ${heighlight && 'tw-border-primary tw-shadow-te-primary'}`} style={{ backgroundColor: tag.color ? tag.color : "#666" }}>
<div className="tw-card-actions tw-justify-end">
</div><b>#{decodeTag(tag.name)}</b>
</div>