first working attestation prototype

This commit is contained in:
Anton Tranelis 2024-07-31 09:25:14 +02:00
parent 4f92c5b4b4
commit bc8b73451c
4 changed files with 103 additions and 115 deletions

View File

@ -2,7 +2,7 @@ import { MapOverlayPage } from '../Templates'
import { useItems, useRemoveItem, useUpdateItem } from '../Map/hooks/useItems' import { useItems, useRemoveItem, useUpdateItem } from '../Map/hooks/useItems'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Item, Tag } from '../../types'; import { Item, ItemsApi, Tag } from '../../types';
import { useMap } from 'react-leaflet'; import { useMap } from 'react-leaflet';
import { LatLng } from 'leaflet'; import { LatLng } from 'leaflet';
import { useHasUserPermission } from '../Map/hooks/usePermissions'; import { useHasUserPermission } from '../Map/hooks/usePermissions';
@ -17,7 +17,7 @@ import { SimpleView } from './Templates/SimpleView';
import { handleDelete, linkItem, unlinkItem } from './itemFunctions'; import { handleDelete, linkItem, unlinkItem } from './itemFunctions';
import { useTags } from '../Map/hooks/useTags'; import { useTags } from '../Map/hooks/useTags';
export function ProfileView({ userType }: { userType: string }) { export function ProfileView({ userType, attestationApi }: { userType: string , attestationApi?: ItemsApi<any>}) {
const [item, setItem] = useState<Item>({} as Item) const [item, setItem] = useState<Item>({} as Item)
const [updatePermission, setUpdatePermission] = useState<boolean>(false); const [updatePermission, setUpdatePermission] = useState<boolean>(false);
@ -40,6 +40,23 @@ export function ProfileView({ userType }: { userType: string }) {
const clusterRef = useClusterRef(); const clusterRef = useClusterRef();
const leafletRefs = useLeafletRefs(); const leafletRefs = useLeafletRefs();
const [attestations, setAttestations] = useState<Array<any>>([]);
useEffect(() => {
if (attestationApi) {
attestationApi.getItems()
.then(value => {
console.log(value);
setAttestations(value);
})
.catch(error => {
console.error("Error fetching items:", error);
});
}
}, [attestationApi])
useEffect(() => { useEffect(() => {
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);
@ -140,7 +157,7 @@ export function ProfileView({ userType }: { userType: string }) {
} }
{template == "tabs" && {template == "tabs" &&
<TabsView setUrlParams={setUrlParams} item={item} loading={loading} offers={offers} needs={needs} relations={relations} updatePermission={updatePermission} linkItem={(id) => linkItem(id, item, updateItem)} unlinkItem={(id) => unlinkItem(id, item, updateItem)}/> <TabsView userType={userType} attestations={attestations} setUrlParams={setUrlParams} item={item} loading={loading} offers={offers} needs={needs} relations={relations} updatePermission={updatePermission} linkItem={(id) => linkItem(id, item, updateItem)} unlinkItem={(id) => unlinkItem(id, item, updateItem)}/>
} }
</> </>

View File

@ -6,8 +6,12 @@ import { useCallback, useEffect, useRef, useState } from 'react'
import { useAddFilterTag } from '../../Map/hooks/useFilter' import { useAddFilterTag } from '../../Map/hooks/useFilter'
import { Item, Tag } from 'utopia-ui/dist/types' import { Item, Tag } from 'utopia-ui/dist/types'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useItems } from '../../Map/hooks/useItems'
import { useAssetApi } from '../../AppShell/hooks/useAssets'
import { timeAgo } from '../../../Utils/TimeAgo'
import { useAuth } from '../../Auth'
export const TabsView = ({ item, offers, needs, relations, updatePermission, loading, linkItem, unlinkItem, setUrlParams }: { item: Item, offers: Array<Tag>, needs: Array<Tag>, relations: Array<Item>, updatePermission: boolean, loading: boolean, linkItem: (id: string) => Promise<void>, unlinkItem: (id: string) => Promise<void> , setUrlParams: any}) => { export const TabsView = ({ attestations, userType, item, offers, needs, relations, updatePermission, loading, linkItem, unlinkItem, setUrlParams }: { attestations: Array<any>, userType: string, item: Item, offers: Array<Tag>, needs: Array<Tag>, relations: Array<Item>, updatePermission: boolean, loading: boolean, linkItem: (id: string) => Promise<void>, unlinkItem: (id: string) => Promise<void>, setUrlParams: any }) => {
const addFilterTag = useAddFilterTag(); const addFilterTag = useAddFilterTag();
const [activeTab, setActiveTab] = useState<number>(); const [activeTab, setActiveTab] = useState<number>();
@ -15,6 +19,14 @@ export const TabsView = ({ item, offers, needs, relations, updatePermission, loa
const [addItemPopupType, setAddItemPopupType] = useState<string>(""); const [addItemPopupType, setAddItemPopupType] = useState<string>("");
const items = useItems();
const assetsApi = useAssetApi();
const {user} = useAuth();
const getUserProfile = (id: string) => {
return items.find(i => i.user_created.id === id && i.layer?.itemType.name === userType)
}
useEffect(() => { useEffect(() => {
scroll(); scroll();
}, [addItemPopupType]) }, [addItemPopupType])
@ -42,57 +54,6 @@ export const TabsView = ({ item, offers, needs, relations, updatePermission, loa
setActiveTab(urlTab ? Number(urlTab) : 1); setActiveTab(urlTab ? Number(urlTab) : 1);
}, [location.search]); }, [location.search]);
const attestations = [{
from: "Timo",
avatar: "https://api.utopia-lab.org/assets/262117f8-feb6-444f-9bd2-e84087285760?width=80&heigth=80",
symbol: "🥇",
text: "1. Platz im Bogenschießen",
date: "21.06.2024",
},
{
from: "Sebastian",
avatar: "https://api.utopia-lab.org/assets/7510a082-882b-41c3-aa7d-5a19f9502f25?width=80&heigth=80",
symbol: "🌱",
text: "danke fürs Rasen mähen",
date: "29.06.2024",
},
{
from: "Yurij",
avatar: "https://api.utopia-lab.org/assets/abe62291-35ad-45de-b978-e5906d8a3eb6?width=80&heigth=80",
symbol: "🏆",
text: "bester Coder ever",
date: "04.07.2024",
},
{
from: "Luca",
avatar: "https://api.utopia-lab.org/assets/e285e653-36e8-4211-a69d-00053c1f610e?width=80&heigth=80",
symbol: "🙏",
text: "Vielen Dank für deine Hilfe!!!",
date: "04.07.2024",
},
{
from: "Lisa",
avatar: "https://i.pinimg.com/originals/c0/ed/08/c0ed088cd6532d4fd27396aefddac57c.jpg",
symbol: "❤️",
text: "Vielen Dank für deine Hilfe!!!",
date: "04.07.2024",
},
{
from: "Timo",
avatar: "https://api.utopia-lab.org/assets/262117f8-feb6-444f-9bd2-e84087285760?width=80&heigth=80",
symbol: "🥈",
text: "2. Platz im Bogenschießen",
date: "21.06.2024",
},
{
from: "Anton",
avatar: "https://api.utopia-lab.org/assets/007dc678-6073-4ad1-9b47-f2cfe1dca582?width=80&heigth=80",
symbol: "🌱",
text: "danke fürs Rasen mähen",
date: "29.06.2024"
},
]
return ( return (
<div role="tablist" className="tw-tabs tw-tabs-lifted tw-mt-2 tw-mb-2 tw-px-6"> <div role="tablist" className="tw-tabs tw-tabs-lifted tw-mt-2 tw-mb-2 tw-px-6">
<input type="radio" name="my_tabs_2" role="tab" <input type="radio" name="my_tabs_2" role="tab"
@ -106,7 +67,7 @@ export const TabsView = ({ item, offers, needs, relations, updatePermission, loa
} }
<TextView item={item} /> <TextView item={item} />
<div className='tw-h-4'></div> <div className='tw-h-4'></div>
<TextView item={item} itemTextField='contact'/> <TextView item={item} itemTextField='contact' />
</div> </div>
{item.layer?.itemType.questlog && {item.layer?.itemType.questlog &&
<> <>
@ -119,9 +80,14 @@ export const TabsView = ({ item, offers, needs, relations, updatePermission, loa
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"> 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">
<table className="sm:tw-table-sm md:tw-table-md"> <table className="sm:tw-table-sm md:tw-table-md">
<tbody> <tbody>
{attestations.map((a, i) => <tr key={i}> {attestations.filter(a => a.to.some(t => t.directus_users_id == item.user_created.id)).map((a, i) => <tr key={i}>
<td> <td>
<div className='tw-mask tw-mask-circle tw-text-xl md:tw-text-2xl tw-bg-slate-200 tw-rounded-full tw-p-2 tw-my-1 tw-mr-2'>{a.symbol}</div> <div
className={`tw-cursor-pointer tw-text-3xl tw-mask tw-mask-${a.shape} tw-p-3 tw-mr-2 tw-bg-[${a.color}]`}
>
{a.emoji}
</div>
</td> </td>
<td> <td>
@ -133,13 +99,13 @@ export const TabsView = ({ item, offers, needs, relations, updatePermission, loa
<div className="tw-avatar"> <div className="tw-avatar">
<div className="tw-mask tw-rounded-full h-8 w-8 tw-mr-2"> <div className="tw-mask tw-rounded-full h-8 w-8 tw-mr-2">
<img <img
src={a.avatar} src={assetsApi.url + getUserProfile(a.user_created.id)?.image}
alt="Avatar Tailwind CSS Component" /> alt="Avatar Tailwind CSS Component" />
</div> </div>
</div> </div>
<div> <div>
<div className="font-bold">{a.from}</div> <div className="font-bold">{getUserProfile(a.user_created.id)?.name}</div>
<div className="tw-text-xs opacity-50 tw-text-zinc-500">{a.date}</div> <div className="tw-text-xs opacity-50 tw-text-zinc-500">{timeAgo(a.date_created)}</div>
</div> </div>
</div> </div>

View File

@ -3,16 +3,17 @@ import { MapOverlayPage } from './MapOverlayPage'
import { useItems } from '../Map/hooks/useItems' import { useItems } from '../Map/hooks/useItems'
import { useAssetApi } from '../AppShell/hooks/useAssets' import { useAssetApi } from '../AppShell/hooks/useAssets'
import { EmojiPicker } from './EmojiPicker'; import { EmojiPicker } from './EmojiPicker';
import { Link } from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import { useRef, useState } from 'react'; import { useRef, useState } from 'react';
import { Item, ItemsApi } from '../../types'; import { Item, ItemsApi } from '../../types';
import { useEffect } from 'react'; import { useEffect } from 'react';
export const AttestationForm = ({api}:{api:ItemsApi<any>}) => { export const AttestationForm = ({api}:{api?:ItemsApi<any>}) => {
const items = useItems(); const items = useItems();
const assetsApi = useAssetApi(); const assetsApi = useAssetApi();
const [users, setUsers] = useState<Array<Item>>(); const [users, setUsers] = useState<Array<Item>>();
const navigate = useNavigate();
useEffect(() => { useEffect(() => {
let params = new URLSearchParams(location.search); let params = new URLSearchParams(location.search);
@ -35,16 +36,22 @@ export const AttestationForm = ({api}:{api:ItemsApi<any>}) => {
}; };
const sendAttestation = async () => { const sendAttestation = async () => {
api.createItem && api.createItem({ const to : Array<any> = [];
users?.map(u => to.push({ directus_users_id: u.user_created.id }));
console.log(to);
api?.createItem && api.createItem({
text: inputValue, text: inputValue,
symbol: "🔥", emoji: selectedEmoji,
color: "", color: selectedColor,
shape: "", shape: selectedShape,
to: users to: to
}) }).then(()=> navigate("/"))
} }
const [selectedEmoji, setSelectedEmoji] = useState('select badge');
const [selectedShape, setSelectedShape] = useState('circle');
const [selectedColor, setSelectedColor] = useState('#fff0d6');
return ( return (
@ -70,7 +77,7 @@ export const AttestationForm = ({api}:{api:ItemsApi<any>}) => {
<div className='tw-w-full'> <div className='tw-w-full'>
<div className='tw-flex tw-justify-center tw-items-center'> <div className='tw-flex tw-justify-center tw-items-center'>
<div className=' tw-flex tw-justify-center tw-items-center tw-w-28 tw-h-28 tw-m-4'> <div className=' tw-flex tw-justify-center tw-items-center tw-w-28 tw-h-28 tw-m-4'>
<EmojiPicker /> <EmojiPicker selectedEmoji={selectedEmoji} selectedColor={selectedColor} selectedShape={selectedShape} setSelectedEmoji={setSelectedEmoji} setSelectedColor={setSelectedColor} setSelectedShape={setSelectedShape} />
</div> </div>
</div> </div>
<div className='tw-flex tw-justify-center tw-items-center'> <div className='tw-flex tw-justify-center tw-items-center'>
@ -82,7 +89,7 @@ export const AttestationForm = ({api}:{api:ItemsApi<any>}) => {
className="tw-input tw-min-w-0 tw-w-fit tw-resize-none tw-overflow-hidden tw-text-center " /> className="tw-input tw-min-w-0 tw-w-fit tw-resize-none tw-overflow-hidden tw-text-center " />
</div> </div>
</div> </div>
<div className='tw-w-full tw-grid tw-mt-4'><Link className="tw-place-self-center" to="/item/b42a1404-fe08-4d84-8404-47ce623c3cf2?tab=2"><button className="tw-btn tw-px-8">Next</button></Link></div> <div className='tw-w-full tw-grid tw-mt-4'><button onClick={sendAttestation} className="tw-btn tw-place-self-center tw-px-8">Next</button></div>
</MapOverlayPage> </MapOverlayPage>
) )
} }

View File

@ -1,9 +1,7 @@
import { useState } from 'react'; import { useState } from 'react';
export const EmojiPicker = () => { export const EmojiPicker = ({selectedEmoji, selectedColor, selectedShape, setSelectedEmoji, setSelectedColor, setSelectedShape}) => {
const [selectedEmoji, setSelectedEmoji] = useState('select badge');
const [selectedShape, setSelectedShape] = useState('circle');
const [selectedColor, setSelectedColor] = useState('#fff0d6');
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);